You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ak...@apache.org on 2015/11/05 04:28:20 UTC
[28/66] [abbrv] ignite git commit: Merge branch ignite-1282 into
ignite-950-new
http://git-wip-us.apache.org/repos/asf/ignite/blob/c050b4ce/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterExImpl.java
----------------------------------------------------------------------
diff --cc modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterExImpl.java
index 75c44b5,0000000..1681e4b
mode 100644,000000..100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterExImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterExImpl.java
@@@ -1,1855 -1,0 +1,1915 @@@
+/*
+ * 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.portable;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.binary.BinaryTypeIdMapper;
+import org.apache.ignite.internal.portable.streams.PortableHeapOutputStream;
+import org.apache.ignite.internal.portable.streams.PortableOutputStream;
+import org.apache.ignite.internal.util.typedef.internal.A;
+import org.apache.ignite.binary.BinaryObjectException;
+import org.apache.ignite.binary.BinaryRawWriter;
+import org.apache.ignite.binary.BinaryWriter;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.IOException;
+import java.io.ObjectOutput;
+import java.lang.reflect.InvocationTargetException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.Timestamp;
+import java.util.Collection;
+import java.util.Date;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.BOOLEAN;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.BOOLEAN_ARR;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.BYTE;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.BYTE_ARR;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.CHAR;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.CHAR_ARR;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.CLASS;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.COL;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.DATE;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.DATE_ARR;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.DECIMAL;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.DECIMAL_ARR;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.DOUBLE;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.DOUBLE_ARR;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.ENUM;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.ENUM_ARR;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.FLAGS_POS;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.FLOAT;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.FLOAT_ARR;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.INT;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.INT_ARR;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.LONG;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.LONG_ARR;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.MAP;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.MAP_ENTRY;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.NULL;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.OBJ;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.OBJ_ARR;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.OPTM_MARSH;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.PORTABLE_OBJ;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.SCHEMA_ID_POS;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.SCHEMA_OR_RAW_OFF_POS;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.SHORT;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.SHORT_ARR;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.STRING;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.STRING_ARR;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.TIMESTAMP;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.TIMESTAMP_ARR;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.TOTAL_LEN_POS;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.UNREGISTERED_TYPE_ID;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.UUID;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.UUID_ARR;
+
+/**
+ * Portable writer implementation.
+ */
+public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, ObjectOutput {
+ /** Length: integer. */
+ private static final int LEN_INT = 4;
+
+ /** */
+ private static final int INIT_CAP = 1024;
+
+ /** FNV1 hash offset basis. */
+ private static final int FNV1_OFFSET_BASIS = 0x811C9DC5;
+
+ /** FNV1 hash prime. */
+ private static final int FNV1_PRIME = 0x01000193;
+
++ /** Maximum offset which fits in 1 byte. */
++ private static final int MAX_OFFSET_1 = 1 << 8;
++
++ /** Maximum offset which fits in 2 bytes. */
++ private static final int MAX_OFFSET_2 = 1 << 16;
++
+ /** Thread-local schema. */
+ private static final ThreadLocal<SchemaHolder> SCHEMA = new ThreadLocal<>();
+
+ /** */
+ private final PortableContext ctx;
+
+ /** */
+ private final int start;
+
+ /** */
+ private Class<?> cls;
+
+ /** */
+ private int typeId;
+
+ /** Raw offset position. */
+ private int rawOffPos;
+
+ /** */
+ private boolean metaEnabled;
+
+ /** */
+ private int metaHashSum;
+
+ /** Handles. */
+ private Map<Object, Integer> handles;
+
+ /** Output stream. */
+ private PortableOutputStream out;
+
+ /** Schema. */
+ private SchemaHolder schema;
+
+ /** Schema ID. */
+ private int schemaId;
+
+ /** Amount of written fields. */
+ private int fieldCnt;
+
+ /** ID mapper. */
+ private BinaryTypeIdMapper idMapper;
+
+ /**
+ * @param ctx Context.
+ */
+ BinaryWriterExImpl(PortableContext ctx) {
+ this(ctx, new PortableHeapOutputStream(INIT_CAP));
+ }
+
+ /**
+ * @param ctx Context.
+ * @param out Output stream.
+ */
+ BinaryWriterExImpl(PortableContext ctx, PortableOutputStream out) {
+ this(ctx, out, new IdentityHashMap<Object, Integer>());
+ }
+
+ /**
+ * @param ctx Context.
+ * @param out Output stream.
+ * @param handles Handles.
+ */
+ private BinaryWriterExImpl(PortableContext ctx, PortableOutputStream out, Map<Object, Integer> handles) {
+ this.ctx = ctx;
+ this.out = out;
+ this.handles = handles;
+
+ start = out.position();
+ }
+
+ /**
+ * @param ctx Context.
+ * @param typeId Type ID.
+ */
+ public BinaryWriterExImpl(PortableContext ctx, int typeId, boolean metaEnabled) {
+ this(ctx);
+
+ this.typeId = typeId;
+ this.metaEnabled = metaEnabled;
+ }
+
+ /**
+ * Close the writer releasing resources if necessary.
+ */
+ @Override public void close() {
+ out.close();
+ }
+
+ /**
+ * @return Meta data hash sum or {@code null} if meta data is disabled.
+ */
+ @Nullable Integer metaDataHashSum() {
+ return metaEnabled ? metaHashSum : null;
+ }
+
+ /**
+ * @param obj Object.
+ * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+ */
+ void marshal(Object obj) throws BinaryObjectException {
+ marshal(obj, true);
+ }
+
+ /**
+ * @param obj Object.
+ * @param enableReplace Object replacing enabled flag.
+ * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+ */
+ void marshal(Object obj, boolean enableReplace) throws BinaryObjectException {
+ assert obj != null;
+
+ cls = obj.getClass();
+
+ PortableClassDescriptor desc = ctx.descriptorForClass(cls);
+
+ if (desc == null)
+ throw new BinaryObjectException("Object is not portable: [class=" + cls + ']');
+
+ if (desc.excluded()) {
+ doWriteByte(NULL);
+ return;
+ }
+
+ if (desc.useOptimizedMarshaller()) {
+ writeByte(OPTM_MARSH);
+
+ try {
+ byte[] arr = ctx.optimizedMarsh().marshal(obj);
+
+ writeInt(arr.length);
+
+ write(arr);
+ }
+ catch (IgniteCheckedException e) {
+ throw new BinaryObjectException("Failed to marshal object with optimized marshaller: " + obj, e);
+ }
+
+ return;
+ }
+
+ if (enableReplace && desc.getWriteReplaceMethod() != null) {
+ Object replacedObj;
+
+ try {
+ replacedObj = desc.getWriteReplaceMethod().invoke(obj);
+ }
+ catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ catch (InvocationTargetException e) {
+ if (e.getTargetException() instanceof BinaryObjectException)
+ throw (BinaryObjectException)e.getTargetException();
+
+ throw new BinaryObjectException("Failed to execute writeReplace() method on " + obj, e);
+ }
+
+ if (replacedObj == null) {
+ doWriteByte(NULL);
+ return;
+ }
+
+ marshal(replacedObj, false);
+
+ return;
+ }
+
+ typeId = desc.typeId();
+
+ metaEnabled = ctx.isMetaDataEnabled(typeId);
+
+ desc.write(obj, this);
+ }
+
+ /**
+ * @param obj Object.
+ * @return Handle.
+ */
+ int handle(Object obj) {
+ assert obj != null;
+
+ Integer h = handles.get(obj);
+
+ if (h != null)
+ return out.position() - h;
+ else {
+ handles.put(obj, out.position());
+
+ return -1;
+ }
+ }
+
+ /**
+ * @return Array.
+ */
+ public byte[] array() {
+ return out.arrayCopy();
+ }
+
+ /**
+ * @return Stream current position.
+ */
+ int position() {
+ return out.position();
+ }
+
+ /**
+ * Sets new position.
+ *
+ * @param pos Position.
+ */
+ void position(int pos) {
+ out.position(pos);
+ }
+
+ /**
+ * @param bytes Number of bytes to reserve.
+ * @return Offset.
+ */
+ public int reserve(int bytes) {
+ int pos = out.position();
+
+ out.position(pos + bytes);
+
+ return pos;
+ }
+
+ /**
+ * Perform post-write activity. This includes:
+ * - writing object length;
+ * - writing schema offset;
+ * - writing schema to the tail.
+ *
+ * @param userType User type flag.
+ */
+ public void postWrite(boolean userType) {
+ if (schema != null) {
+ // Write schema ID.
+ out.writeInt(start + SCHEMA_ID_POS, schemaId);
+
+ // Write schema offset.
+ out.writeInt(start + SCHEMA_OR_RAW_OFF_POS, out.position() - start);
+
+ // Write the schema.
- schema.writeAndPop(this, fieldCnt);
++ int offsetByteCnt = schema.write(this, fieldCnt);
+
+ // Write raw offset if needed.
+ if (rawOffPos != 0)
+ out.writeInt(rawOffPos - start);
++
++ if (offsetByteCnt == PortableUtils.OFFSET_1) {
++ int flags = (userType ? PortableUtils.FLAG_USR_TYP : 0) | PortableUtils.FLAG_OFFSET_ONE_BYTE;
++
++ out.writeShort(start + FLAGS_POS, (short)flags);
++ }
++ else if (offsetByteCnt == PortableUtils.OFFSET_2) {
++ int flags = (userType ? PortableUtils.FLAG_USR_TYP : 0) | PortableUtils.FLAG_OFFSET_TWO_BYTES;
++
++ out.writeShort(start + FLAGS_POS, (short)flags);
++ }
+ }
+ else {
+ // Write raw-only flag is needed.
+ int flags = (userType ? PortableUtils.FLAG_USR_TYP : 0) | PortableUtils.FLAG_RAW_ONLY;
+
+ out.writeShort(start + FLAGS_POS, (short)flags);
+
+ // If there are no schema, we are free to write raw offset to schema offset.
+ out.writeInt(start + SCHEMA_OR_RAW_OFF_POS, (rawOffPos == 0 ? out.position() : rawOffPos) - start);
+ }
+
+ // 5. Write length.
+ out.writeInt(start + TOTAL_LEN_POS, out.position() - start);
+ }
+
+ /**
++ * Pop schema.
++ */
++ public void popSchema() {
++ if (schema != null) {
++ assert fieldCnt > 0;
++
++ schema.pop(fieldCnt);
++ }
++ }
++
++ /**
+ * @param val Byte array.
+ */
+ public void write(byte[] val) {
+ assert val != null;
+
+ out.writeByteArray(val);
+ }
+
+ /**
+ * @param val Byte array.
+ * @param off Offset.
+ * @param len Length.
+ */
+ public void write(byte[] val, int off, int len) {
+ assert val != null;
+
+ out.write(val, off, len);
+ }
+
+ /**
+ * @param val Value.
+ */
+ public void doWriteByte(byte val) {
+ out.writeByte(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ public void doWriteShort(short val) {
+ out.writeShort(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ public void doWriteInt(int val) {
+ out.writeInt(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ public void doWriteLong(long val) {
+ out.writeLong(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ public void doWriteFloat(float val) {
+ out.writeFloat(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ public void doWriteDouble(double val) {
+ out.writeDouble(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ public void doWriteChar(char val) {
+ out.writeChar(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ public void doWriteBoolean(boolean val) {
+ out.writeBoolean(val);
+ }
+
+ /**
+ * @param val String value.
+ */
+ public void doWriteDecimal(@Nullable BigDecimal val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ doWriteByte(DECIMAL);
+
+ BigInteger intVal = val.unscaledValue();
+
+ if (intVal.signum() == -1) {
+ intVal = intVal.negate();
+
+ out.writeInt(val.scale() | 0x80000000);
+ }
+ else
+ out.writeInt(val.scale());
+
+ byte[] vals = intVal.toByteArray();
+
+ out.writeInt(vals.length);
+ out.writeByteArray(vals);
+ }
+ }
+
+ /**
+ * @param val String value.
+ */
+ public void doWriteString(@Nullable String val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ doWriteByte(STRING);
+
+ if (ctx.isConvertString()) {
+ doWriteBoolean(true);
+
+ byte[] strArr = val.getBytes(UTF_8);
+
+ doWriteInt(strArr.length);
+
+ out.writeByteArray(strArr);
+ }
+ else {
+ doWriteBoolean(false);
+
+ char[] strArr = val.toCharArray();
+
+ doWriteInt(strArr.length);
+
+ out.writeCharArray(strArr);
+ }
+ }
+ }
+
+ /**
+ * @param uuid UUID.
+ */
+ public void doWriteUuid(@Nullable UUID uuid) {
+ if (uuid == null)
+ doWriteByte(NULL);
+ else {
+ doWriteByte(UUID);
+ doWriteLong(uuid.getMostSignificantBits());
+ doWriteLong(uuid.getLeastSignificantBits());
+ }
+ }
+
+ /**
+ * @param date Date.
+ */
+ public void doWriteDate(@Nullable Date date) {
+ if (date == null)
+ doWriteByte(NULL);
+ else {
+ doWriteByte(DATE);
+ doWriteLong(date.getTime());
+ }
+ }
+
+ /**
+ * @param ts Timestamp.
+ */
+ public void doWriteTimestamp(@Nullable Timestamp ts) {
+ if (ts== null)
+ doWriteByte(NULL);
+ else {
+ doWriteByte(TIMESTAMP);
+ doWriteLong(ts.getTime());
+ doWriteInt(ts.getNanos() % 1000000);
+ }
+ }
+
+ /**
+ * Write object.
+ *
+ * @param obj Object.
+ * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+ */
+ public void doWriteObject(@Nullable Object obj) throws BinaryObjectException {
+ if (obj == null)
+ doWriteByte(NULL);
+ else {
+ BinaryWriterExImpl writer = new BinaryWriterExImpl(ctx, out, handles);
+
+ writer.marshal(obj);
+ }
+ }
+
+ /**
+ * @param val Byte array.
+ */
+ void doWriteByteArray(@Nullable byte[] val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ if (tryWriteAsHandle(val))
+ return;
+
+ doWriteByte(BYTE_ARR);
+ doWriteInt(val.length);
+
+ out.writeByteArray(val);
+ }
+ }
+
+ /**
+ * @param val Short array.
+ */
+ void doWriteShortArray(@Nullable short[] val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ if (tryWriteAsHandle(val))
+ return;
+
+ doWriteByte(SHORT_ARR);
+ doWriteInt(val.length);
+
+ out.writeShortArray(val);
+ }
+ }
+
+ /**
+ * @param val Integer array.
+ */
+ void doWriteIntArray(@Nullable int[] val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ if (tryWriteAsHandle(val))
+ return;
+
+ doWriteByte(INT_ARR);
+ doWriteInt(val.length);
+
+ out.writeIntArray(val);
+ }
+ }
+
+ /**
+ * @param val Long array.
+ */
+ void doWriteLongArray(@Nullable long[] val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ if (tryWriteAsHandle(val))
+ return;
+
+ doWriteByte(LONG_ARR);
+ doWriteInt(val.length);
+
+ out.writeLongArray(val);
+ }
+ }
+
+ /**
+ * @param val Float array.
+ */
+ void doWriteFloatArray(@Nullable float[] val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ if (tryWriteAsHandle(val))
+ return;
+
+ doWriteByte(FLOAT_ARR);
+ doWriteInt(val.length);
+
+ out.writeFloatArray(val);
+ }
+ }
+
+ /**
+ * @param val Double array.
+ */
+ void doWriteDoubleArray(@Nullable double[] val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ if (tryWriteAsHandle(val))
+ return;
+
+ doWriteByte(DOUBLE_ARR);
+ doWriteInt(val.length);
+
+ out.writeDoubleArray(val);
+ }
+ }
+
+ /**
+ * @param val Char array.
+ */
+ void doWriteCharArray(@Nullable char[] val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ if (tryWriteAsHandle(val))
+ return;
+
+ doWriteByte(CHAR_ARR);
+ doWriteInt(val.length);
+
+ out.writeCharArray(val);
+ }
+ }
+
+ /**
+ * @param val Boolean array.
+ */
+ void doWriteBooleanArray(@Nullable boolean[] val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ if (tryWriteAsHandle(val))
+ return;
+
+ doWriteByte(BOOLEAN_ARR);
+ doWriteInt(val.length);
+
+ out.writeBooleanArray(val);
+ }
+ }
+
+ /**
+ * @param val Array of strings.
+ */
+ void doWriteDecimalArray(@Nullable BigDecimal[] val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ if (tryWriteAsHandle(val))
+ return;
+
+ doWriteByte(DECIMAL_ARR);
+ doWriteInt(val.length);
+
+ for (BigDecimal str : val)
+ doWriteDecimal(str);
+ }
+ }
+
+ /**
+ * @param val Array of strings.
+ */
+ void doWriteStringArray(@Nullable String[] val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ if (tryWriteAsHandle(val))
+ return;
+
+ doWriteByte(STRING_ARR);
+ doWriteInt(val.length);
+
+ for (String str : val)
+ doWriteString(str);
+ }
+ }
+
+ /**
+ * @param val Array of UUIDs.
+ */
+ void doWriteUuidArray(@Nullable UUID[] val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ if (tryWriteAsHandle(val))
+ return;
+
+ doWriteByte(UUID_ARR);
+ doWriteInt(val.length);
+
+ for (UUID uuid : val)
+ doWriteUuid(uuid);
+ }
+ }
+
+ /**
+ * @param val Array of dates.
+ */
+ void doWriteDateArray(@Nullable Date[] val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ if (tryWriteAsHandle(val))
+ return;
+
+ doWriteByte(DATE_ARR);
+ doWriteInt(val.length);
+
+ for (Date date : val)
+ doWriteDate(date);
+ }
+ }
+
+ /**
+ * @param val Array of timestamps.
+ */
+ void doWriteTimestampArray(@Nullable Timestamp[] val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ if (tryWriteAsHandle(val))
+ return;
+
+ doWriteByte(TIMESTAMP_ARR);
+ doWriteInt(val.length);
+
+ for (Timestamp ts : val)
+ doWriteTimestamp(ts);
+ }
+ }
+
+ /**
+ * @param val Array of objects.
+ * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+ */
+ void doWriteObjectArray(@Nullable Object[] val) throws BinaryObjectException {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ if (tryWriteAsHandle(val))
+ return;
+
+ PortableClassDescriptor desc = ctx.descriptorForClass(val.getClass().getComponentType());
+
+ doWriteByte(OBJ_ARR);
+
+ if (desc.registered())
+ doWriteInt(desc.typeId());
+ else {
+ doWriteInt(UNREGISTERED_TYPE_ID);
+ doWriteString(val.getClass().getComponentType().getName());
+ }
+
+ doWriteInt(val.length);
+
+ for (Object obj : val)
+ doWriteObject(obj);
+ }
+ }
+
+ /**
+ * @param col Collection.
+ * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+ */
+ void doWriteCollection(@Nullable Collection<?> col) throws BinaryObjectException {
+ if (col == null)
+ doWriteByte(NULL);
+ else {
+ if (tryWriteAsHandle(col))
+ return;
+
+ doWriteByte(COL);
+ doWriteInt(col.size());
+ doWriteByte(ctx.collectionType(col.getClass()));
+
+ for (Object obj : col)
+ doWriteObject(obj);
+ }
+ }
+
+ /**
+ * @param map Map.
+ * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+ */
+ void doWriteMap(@Nullable Map<?, ?> map) throws BinaryObjectException {
+ if (map == null)
+ doWriteByte(NULL);
+ else {
+ if (tryWriteAsHandle(map))
+ return;
+
+ doWriteByte(MAP);
+ doWriteInt(map.size());
+ doWriteByte(ctx.mapType(map.getClass()));
+
+ for (Map.Entry<?, ?> e : map.entrySet()) {
+ doWriteObject(e.getKey());
+ doWriteObject(e.getValue());
+ }
+ }
+ }
+
+ /**
+ * @param e Map entry.
+ * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+ */
+ void doWriteMapEntry(@Nullable Map.Entry<?, ?> e) throws BinaryObjectException {
+ if (e == null)
+ doWriteByte(NULL);
+ else {
+ if (tryWriteAsHandle(e))
+ return;
+
+ doWriteByte(MAP_ENTRY);
+ doWriteObject(e.getKey());
+ doWriteObject(e.getValue());
+ }
+ }
+
+ /**
+ * @param val Value.
+ */
+ void doWriteEnum(@Nullable Enum<?> val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ PortableClassDescriptor desc = ctx.descriptorForClass(val.getClass());
+
+ doWriteByte(ENUM);
+
+ if (desc.registered())
+ doWriteInt(desc.typeId());
+ else {
+ doWriteInt(UNREGISTERED_TYPE_ID);
+ doWriteString(val.getClass().getName());
+ }
+
+ doWriteInt(val.ordinal());
+ }
+ }
+
+ /**
+ * @param val Array.
+ */
+ void doWriteEnumArray(@Nullable Object[] val) {
+ assert val == null || val.getClass().getComponentType().isEnum();
+
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ PortableClassDescriptor desc = ctx.descriptorForClass(val.getClass().getComponentType());
+ doWriteByte(ENUM_ARR);
+
+ if (desc.registered())
+ doWriteInt(desc.typeId());
+ else {
+ doWriteInt(UNREGISTERED_TYPE_ID);
+ doWriteString(val.getClass().getComponentType().getName());
+ }
+
+ doWriteInt(val.length);
+
+ // TODO: Denis: Redundant data for each element of the array.
+ for (Object o : val)
+ doWriteEnum((Enum<?>)o);
+ }
+ }
+
+ /**
+ * @param val Class.
+ */
+ void doWriteClass(@Nullable Class val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ PortableClassDescriptor desc = ctx.descriptorForClass(val);
+
+ doWriteByte(CLASS);
+
+ if (desc.registered())
+ doWriteInt(desc.typeId());
+ else {
+ doWriteInt(UNREGISTERED_TYPE_ID);
+ doWriteString(val.getClass().getName());
+ }
+ }
+ }
+
+ /**
+ * @param po Portable object.
+ */
+ public void doWritePortableObject(@Nullable BinaryObjectImpl po) {
+ if (po == null)
+ doWriteByte(NULL);
+ else {
+ doWriteByte(PORTABLE_OBJ);
+
+ byte[] poArr = po.array();
+
+ doWriteInt(poArr.length);
+
+ out.writeByteArray(poArr);
+
+ doWriteInt(po.start());
+ }
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeByteField(@Nullable Byte val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ doWriteByte(BYTE);
+ doWriteByte(val);
+ }
+ }
+
+ /**
+ * @param val Class.
+ */
+ void writeClassField(@Nullable Class val) {
+ doWriteClass(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeShortField(@Nullable Short val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ doWriteByte(SHORT);
+ doWriteShort(val);
+ }
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeIntField(@Nullable Integer val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ doWriteByte(INT);
+ doWriteInt(val);
+ }
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeLongField(@Nullable Long val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ doWriteByte(LONG);
+ doWriteLong(val);
+ }
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeFloatField(@Nullable Float val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ doWriteByte(FLOAT);
+ doWriteFloat(val);
+ }
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeDoubleField(@Nullable Double val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ doWriteByte(DOUBLE);
+ doWriteDouble(val);
+ }
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeCharField(@Nullable Character val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ doWriteByte(CHAR);
+ doWriteChar(val);
+ }
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeBooleanField(@Nullable Boolean val) {
+ if (val == null)
+ doWriteByte(NULL);
+ else {
+ doWriteByte(BOOLEAN);
+ doWriteBoolean(val);
+ }
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeDecimalField(@Nullable BigDecimal val) {
+ doWriteDecimal(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeStringField(@Nullable String val) {
+ doWriteString(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeUuidField(@Nullable UUID val) {
+ doWriteUuid(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeDateField(@Nullable Date val) {
+ doWriteDate(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeTimestampField(@Nullable Timestamp val) {
+ doWriteTimestamp(val);
+ }
+
+ /**
+ * @param obj Object.
+ * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+ */
+ void writeObjectField(@Nullable Object obj) throws BinaryObjectException {
+ doWriteObject(obj);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeByteArrayField(@Nullable byte[] val) {
+ doWriteByteArray(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeShortArrayField(@Nullable short[] val) {
+ doWriteShortArray(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeIntArrayField(@Nullable int[] val) {
+ doWriteIntArray(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeLongArrayField(@Nullable long[] val) {
+ doWriteLongArray(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeFloatArrayField(@Nullable float[] val) {
+ doWriteFloatArray(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeDoubleArrayField(@Nullable double[] val) {
+ doWriteDoubleArray(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeCharArrayField(@Nullable char[] val) {
+ doWriteCharArray(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeBooleanArrayField(@Nullable boolean[] val) {
+ doWriteBooleanArray(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeDecimalArrayField(@Nullable BigDecimal[] val) {
+ doWriteDecimalArray(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeStringArrayField(@Nullable String[] val) {
+ doWriteStringArray(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeUuidArrayField(@Nullable UUID[] val) {
+ doWriteUuidArray(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeDateArrayField(@Nullable Date[] val) {
+ doWriteDateArray(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeTimestampArrayField(@Nullable Timestamp[] val) {
+ doWriteTimestampArray(val);
+ }
+
+ /**
+ * @param val Value.
+ * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+ */
+ void writeObjectArrayField(@Nullable Object[] val) throws BinaryObjectException {
+ doWriteObjectArray(val);
+ }
+
+ /**
+ * @param col Collection.
+ * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+ */
+ void writeCollectionField(@Nullable Collection<?> col) throws BinaryObjectException {
+ doWriteCollection(col);
+ }
+
+ /**
+ * @param map Map.
+ * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+ */
+ void writeMapField(@Nullable Map<?, ?> map) throws BinaryObjectException {
+ doWriteMap(map);
+ }
+
+ /**
+ * @param e Map entry.
+ * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+ */
+ void writeMapEntryField(@Nullable Map.Entry<?, ?> e) throws BinaryObjectException {
+ doWriteMapEntry(e);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeEnumField(@Nullable Enum<?> val) {
+ doWriteEnum(val);
+ }
+
+ /**
+ * @param val Value.
+ */
+ void writeEnumArrayField(@Nullable Object[] val) {
+ doWriteEnumArray(val);
+ }
+
+ /**
+ * @param po Portable object.
+ * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+ */
+ void writePortableObjectField(@Nullable BinaryObjectImpl po) throws BinaryObjectException {
+ doWritePortableObject(po);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeByte(String fieldName, byte val) throws BinaryObjectException {
+ writeFieldId(fieldName, BYTE);
+ writeByteField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeByte(byte val) throws BinaryObjectException {
+ doWriteByte(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeShort(String fieldName, short val) throws BinaryObjectException {
+ writeFieldId(fieldName, SHORT);
+ writeShortField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeShort(short val) throws BinaryObjectException {
+ doWriteShort(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeInt(String fieldName, int val) throws BinaryObjectException {
+ writeFieldId(fieldName, INT);
+ writeIntField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeInt(int val) throws BinaryObjectException {
+ doWriteInt(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeLong(String fieldName, long val) throws BinaryObjectException {
+ writeFieldId(fieldName, LONG);
+ writeLongField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeLong(long val) throws BinaryObjectException {
+ doWriteLong(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeFloat(String fieldName, float val) throws BinaryObjectException {
+ writeFieldId(fieldName, FLOAT);
+ writeFloatField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeFloat(float val) throws BinaryObjectException {
+ doWriteFloat(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeDouble(String fieldName, double val) throws BinaryObjectException {
+ writeFieldId(fieldName, DOUBLE);
+ writeDoubleField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeDouble(double val) throws BinaryObjectException {
+ doWriteDouble(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeChar(String fieldName, char val) throws BinaryObjectException {
+ writeFieldId(fieldName, CHAR);
+ writeCharField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeChar(char val) throws BinaryObjectException {
+ doWriteChar(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeBoolean(String fieldName, boolean val) throws BinaryObjectException {
+ writeFieldId(fieldName, BOOLEAN);
+ writeBooleanField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeBoolean(boolean val) throws BinaryObjectException {
+ doWriteBoolean(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeDecimal(String fieldName, @Nullable BigDecimal val) throws BinaryObjectException {
+ writeFieldId(fieldName, DECIMAL);
+ writeDecimalField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeDecimal(@Nullable BigDecimal val) throws BinaryObjectException {
+ doWriteDecimal(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeString(String fieldName, @Nullable String val) throws BinaryObjectException {
+ writeFieldId(fieldName, STRING);
+ writeStringField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeString(@Nullable String val) throws BinaryObjectException {
+ doWriteString(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeUuid(String fieldName, @Nullable UUID val) throws BinaryObjectException {
+ writeFieldId(fieldName, UUID);
+ writeUuidField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeUuid(@Nullable UUID val) throws BinaryObjectException {
+ doWriteUuid(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeDate(String fieldName, @Nullable Date val) throws BinaryObjectException {
+ writeFieldId(fieldName, DATE);
+ writeDateField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeDate(@Nullable Date val) throws BinaryObjectException {
+ doWriteDate(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeTimestamp(String fieldName, @Nullable Timestamp val) throws BinaryObjectException {
+ writeFieldId(fieldName, TIMESTAMP);
+ writeTimestampField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeTimestamp(@Nullable Timestamp val) throws BinaryObjectException {
+ doWriteTimestamp(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeObject(String fieldName, @Nullable Object obj) throws BinaryObjectException {
+ writeFieldId(fieldName, OBJ);
+ writeObjectField(obj);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeObject(@Nullable Object obj) throws BinaryObjectException {
+ doWriteObject(obj);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeObjectDetached(@Nullable Object obj) throws BinaryObjectException {
+ if (obj == null)
+ doWriteByte(NULL);
+ else {
+ BinaryWriterExImpl writer = new BinaryWriterExImpl(ctx, out, new IdentityHashMap<Object, Integer>());
+
+ writer.marshal(obj);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeByteArray(String fieldName, @Nullable byte[] val) throws BinaryObjectException {
+ writeFieldId(fieldName, BYTE_ARR);
+ writeByteArrayField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeByteArray(@Nullable byte[] val) throws BinaryObjectException {
+ doWriteByteArray(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeShortArray(String fieldName, @Nullable short[] val) throws BinaryObjectException {
+ writeFieldId(fieldName, SHORT_ARR);
+ writeShortArrayField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeShortArray(@Nullable short[] val) throws BinaryObjectException {
+ doWriteShortArray(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeIntArray(String fieldName, @Nullable int[] val) throws BinaryObjectException {
+ writeFieldId(fieldName, INT_ARR);
+ writeIntArrayField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeIntArray(@Nullable int[] val) throws BinaryObjectException {
+ doWriteIntArray(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeLongArray(String fieldName, @Nullable long[] val) throws BinaryObjectException {
+ writeFieldId(fieldName, LONG_ARR);
+ writeLongArrayField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeLongArray(@Nullable long[] val) throws BinaryObjectException {
+ doWriteLongArray(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeFloatArray(String fieldName, @Nullable float[] val) throws BinaryObjectException {
+ writeFieldId(fieldName, FLOAT_ARR);
+ writeFloatArrayField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeFloatArray(@Nullable float[] val) throws BinaryObjectException {
+ doWriteFloatArray(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeDoubleArray(String fieldName, @Nullable double[] val)
+ throws BinaryObjectException {
+ writeFieldId(fieldName, DOUBLE_ARR);
+ writeDoubleArrayField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeDoubleArray(@Nullable double[] val) throws BinaryObjectException {
+ doWriteDoubleArray(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeCharArray(String fieldName, @Nullable char[] val) throws BinaryObjectException {
+ writeFieldId(fieldName, CHAR_ARR);
+ writeCharArrayField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeCharArray(@Nullable char[] val) throws BinaryObjectException {
+ doWriteCharArray(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeBooleanArray(String fieldName, @Nullable boolean[] val)
+ throws BinaryObjectException {
+ writeFieldId(fieldName, BOOLEAN_ARR);
+ writeBooleanArrayField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeBooleanArray(@Nullable boolean[] val) throws BinaryObjectException {
+ doWriteBooleanArray(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeDecimalArray(String fieldName, @Nullable BigDecimal[] val)
+ throws BinaryObjectException {
+ writeFieldId(fieldName, DECIMAL_ARR);
+ writeDecimalArrayField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeDecimalArray(@Nullable BigDecimal[] val) throws BinaryObjectException {
+ doWriteDecimalArray(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeStringArray(String fieldName, @Nullable String[] val)
+ throws BinaryObjectException {
+ writeFieldId(fieldName, STRING_ARR);
+ writeStringArrayField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeStringArray(@Nullable String[] val) throws BinaryObjectException {
+ doWriteStringArray(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeUuidArray(String fieldName, @Nullable UUID[] val) throws BinaryObjectException {
+ writeFieldId(fieldName, UUID_ARR);
+ writeUuidArrayField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeUuidArray(@Nullable UUID[] val) throws BinaryObjectException {
+ doWriteUuidArray(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeDateArray(String fieldName, @Nullable Date[] val) throws BinaryObjectException {
+ writeFieldId(fieldName, DATE_ARR);
+ writeDateArrayField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeDateArray(@Nullable Date[] val) throws BinaryObjectException {
+ doWriteDateArray(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeTimestampArray(String fieldName, @Nullable Timestamp[] val) throws BinaryObjectException {
+ writeFieldId(fieldName, TIMESTAMP_ARR);
+ writeTimestampArrayField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeTimestampArray(@Nullable Timestamp[] val) throws BinaryObjectException {
+ doWriteTimestampArray(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeObjectArray(String fieldName, @Nullable Object[] val) throws BinaryObjectException {
+ writeFieldId(fieldName, OBJ_ARR);
+ writeObjectArrayField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeObjectArray(@Nullable Object[] val) throws BinaryObjectException {
+ doWriteObjectArray(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public <T> void writeCollection(String fieldName, @Nullable Collection<T> col)
+ throws BinaryObjectException {
+ writeFieldId(fieldName, COL);
+ writeCollectionField(col);
+ }
+
+ /** {@inheritDoc} */
+ @Override public <T> void writeCollection(@Nullable Collection<T> col) throws BinaryObjectException {
+ doWriteCollection(col);
+ }
+
+ /** {@inheritDoc} */
+ @Override public <K, V> void writeMap(String fieldName, @Nullable Map<K, V> map)
+ throws BinaryObjectException {
+ writeFieldId(fieldName, MAP);
+ writeMapField(map);
+ }
+
+ /** {@inheritDoc} */
+ @Override public <K, V> void writeMap(@Nullable Map<K, V> map) throws BinaryObjectException {
+ doWriteMap(map);
+ }
+
+ /** {@inheritDoc} */
+ @Override public <T extends Enum<?>> void writeEnum(String fieldName, T val) throws BinaryObjectException {
+ writeFieldId(fieldName, ENUM);
+ writeEnumField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public <T extends Enum<?>> void writeEnum(T val) throws BinaryObjectException {
+ doWriteEnum(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public <T extends Enum<?>> void writeEnumArray(String fieldName, T[] val) throws BinaryObjectException {
+ writeFieldId(fieldName, ENUM_ARR);
+ writeEnumArrayField(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public <T extends Enum<?>> void writeEnumArray(T[] val) throws BinaryObjectException {
+ doWriteEnumArray(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public BinaryRawWriter rawWriter() {
+ if (rawOffPos == 0)
+ rawOffPos = out.position();
+
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ @Override public PortableOutputStream out() {
+ return out;
+ }
+
+ /** {@inheritDoc} */
+ @SuppressWarnings("NullableProblems")
+ @Override public void writeBytes(String s) throws IOException {
+ int len = s.length();
+
+ writeInt(len);
+
+ for (int i = 0; i < len; i++)
+ writeByte(s.charAt(i));
+ }
+
+ /** {@inheritDoc} */
+ @SuppressWarnings("NullableProblems")
+ @Override public void writeChars(String s) throws IOException {
+ int len = s.length();
+
+ writeInt(len);
+
+ for (int i = 0; i < len; i++)
+ writeChar(s.charAt(i));
+ }
+
+ /** {@inheritDoc} */
+ @SuppressWarnings("NullableProblems")
+ @Override public void writeUTF(String s) throws IOException {
+ writeString(s);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeByte(int v) throws IOException {
+ doWriteByte((byte) v);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeShort(int v) throws IOException {
+ doWriteShort((short) v);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeChar(int v) throws IOException {
+ doWriteChar((char) v);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void write(int b) throws IOException {
+ doWriteByte((byte) b);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void flush() throws IOException {
+ // No-op.
+ }
+
+ /** {@inheritDoc} */
+ @Override public int reserveInt() {
+ return reserve(LEN_INT);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeInt(int pos, int val) throws BinaryObjectException {
+ out.writeInt(pos, val);
+ }
+
+ /**
+ * @param fieldName Field name.
+ * @throws org.apache.ignite.binary.BinaryObjectException If fields are not allowed.
+ */
+ private void writeFieldId(String fieldName, byte fieldType) throws BinaryObjectException {
+ A.notNull(fieldName, "fieldName");
+
+ if (rawOffPos != 0)
+ throw new BinaryObjectException("Individual field can't be written after raw writer is acquired " +
+ "via rawWriter() method. Consider fixing serialization logic for class: " + cls.getName());
+
+ if (idMapper == null)
+ idMapper = ctx.userTypeIdMapper(typeId);
+
+ int id = idMapper.fieldId(typeId, fieldName);
+
+ writeFieldId(id);
+
+ if (metaEnabled)
+ metaHashSum = 31 * metaHashSum + (id + fieldType);
+ }
+
+ /**
+ * Write field ID.
+ * @param fieldId Field ID.
+ */
+ public void writeFieldId(int fieldId) {
+ int fieldOff = out.position() - start;
+
+ if (schema == null) {
+ schema = SCHEMA.get();
+
+ if (schema == null) {
+ schema = new SchemaHolder();
+
+ SCHEMA.set(schema);
+ }
+
+ // Initialize offset when the first field is written.
+ schemaId = FNV1_OFFSET_BASIS;
+ }
+
+ // Advance schema hash.
+ int schemaId0 = schemaId ^ (fieldId & 0xFF);
+ schemaId0 = schemaId0 * FNV1_PRIME;
+ schemaId0 = schemaId0 ^ ((fieldId >> 8) & 0xFF);
+ schemaId0 = schemaId0 * FNV1_PRIME;
+ schemaId0 = schemaId0 ^ ((fieldId >> 16) & 0xFF);
+ schemaId0 = schemaId0 * FNV1_PRIME;
+ schemaId0 = schemaId0 ^ ((fieldId >> 24) & 0xFF);
+ schemaId0 = schemaId0 * FNV1_PRIME;
+
+ schemaId = schemaId0;
+
+ schema.push(fieldId, fieldOff);
+
+ fieldCnt++;
+ }
+
+ /**
+ * Attempts to write the object as a handle.
+ *
+ * @param obj Object to write.
+ * @return {@code true} if the object has been written as a handle.
+ */
+ boolean tryWriteAsHandle(Object obj) {
+ int handle = handle(obj);
+
+ if (handle >= 0) {
+ doWriteByte(GridPortableMarshaller.HANDLE);
+ doWriteInt(handle);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Create new writer with same context.
+ *
+ * @param typeId type
+ * @return New writer.
+ */
+ public BinaryWriterExImpl newWriter(int typeId) {
+ BinaryWriterExImpl res = new BinaryWriterExImpl(ctx, out, handles);
+
+ res.typeId = typeId;
+
+ return res;
+ }
+
+ /**
+ * @return Portable context.
+ */
+ public PortableContext context() {
+ return ctx;
+ }
+
+ /**
+ * Schema holder.
+ */
+ private static class SchemaHolder {
+ /** Grow step. */
+ private static final int GROW_STEP = 16;
+
+ /** Maximum stable size. */
+ private static final int MAX_SIZE = 256;
+
+ /** Data. */
+ private int[] data;
+
+ /** Index. */
+ private int idx;
+
+ /**
+ * Constructor.
+ */
+ public SchemaHolder() {
+ data = new int[GROW_STEP];
+ }
+
+ /**
+ * Push another frame.
+ *
+ * @param id Field ID.
+ * @param off Field offset.
+ */
+ public void push(int id, int off) {
+ if (idx == data.length) {
+ int[] data0 = new int[data.length + GROW_STEP];
+
+ System.arraycopy(data, 0, data0, 0, data.length);
+
+ data = data0;
+ }
+
+ data[idx] = id;
+ data[idx + 1] = off;
+
+ idx += 2;
+ }
+
+ /**
+ * Write collected frames and pop them.
+ *
+ * @param writer Writer.
- * @param cnt Count.
++ * @param fieldCnt Count.
++ * @return Amount of bytes dedicated to
+ */
- public void writeAndPop(BinaryWriterExImpl writer, int cnt) {
- int startIdx = idx - cnt * 2;
++ public int write(BinaryWriterExImpl writer, int fieldCnt) {
++ int startIdx = idx - fieldCnt * 2;
+
+ assert startIdx >= 0;
+
- for (int idx0 = startIdx; idx0 < idx;) {
- writer.writeInt(data[idx0++]);
- writer.writeInt(data[idx0++]);
++ int lastOffset = data[idx - 1];
++
++ int res;
++
++ if (lastOffset < MAX_OFFSET_1) {
++ for (int idx0 = startIdx; idx0 < idx; ) {
++ writer.writeInt(data[idx0++]);
++ writer.writeByte((byte) data[idx0++]);
++ }
++
++ res = PortableUtils.OFFSET_1;
+ }
++ else if (lastOffset < MAX_OFFSET_2) {
++ for (int idx0 = startIdx; idx0 < idx; ) {
++ writer.writeInt(data[idx0++]);
++ writer.writeShort((short)data[idx0++]);
++ }
++
++ res = PortableUtils.OFFSET_2;
++ }
++ else {
++ for (int idx0 = startIdx; idx0 < idx; ) {
++ writer.writeInt(data[idx0++]);
++ writer.writeInt(data[idx0++]);
++ }
+
- idx = startIdx;
++ res = PortableUtils.OFFSET_4;
++ }
++
++ return res;
++ }
++
++ /**
++ * Pop current object's frame.
++ */
++ public void pop(int fieldCnt) {
++ idx = idx - fieldCnt * 2;
+
+ // Shrink data array if needed.
+ if (idx == 0 && data.length > MAX_SIZE)
+ data = new int[MAX_SIZE];
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/c050b4ce/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java
----------------------------------------------------------------------
diff --cc modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java
index bbd6ad9,aa72017..b95dc3d
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java
@@@ -524,21 -524,26 +524,26 @@@ public class PortableClassDescriptor
case PORTABLE:
if (writeHeader(obj, writer)) {
- if (serializer != null)
- serializer.writeBinary(obj, writer);
- else
- ((Binarylizable)obj).writeBinary(writer);
+ try {
+ if (serializer != null)
- serializer.writePortable(obj, writer);
++ serializer.writeBinary(obj, writer);
+ else
- ((PortableMarshalAware) obj).writePortable(writer);
++ ((Binarylizable)obj).writeBinary(writer);
- writer.postWrite(userType);
+ writer.postWrite(userType);
+ }
+ finally {
+ writer.popSchema();
+ }
- if (obj.getClass() != PortableMetaDataImpl.class
+ if (obj.getClass() != BinaryMetaDataImpl.class
&& ctx.isMetaDataChanged(typeId, writer.metaDataHashSum())) {
- PortableMetaDataCollector metaCollector = new PortableMetaDataCollector(typeName);
+ BinaryMetaDataCollector metaCollector = new BinaryMetaDataCollector(typeName);
if (serializer != null)
- serializer.writePortable(obj, metaCollector);
+ serializer.writeBinary(obj, metaCollector);
else
- ((PortableMarshalAware)obj).writePortable(metaCollector);
+ ((Binarylizable)obj).writeBinary(metaCollector);
ctx.updateMetaData(typeId, typeName, metaCollector.meta());
}
@@@ -552,12 -557,15 +557,15 @@@
try {
((Externalizable)obj).writeExternal(writer);
+
+ writer.postWrite(userType);
}
catch (IOException e) {
- throw new PortableException("Failed to write Externalizable object: " + obj, e);
+ throw new BinaryObjectException("Failed to write Externalizable object: " + obj, e);
}
-
- writer.postWrite(userType);
+ finally {
+ writer.popSchema();
+ }
}
break;
http://git-wip-us.apache.org/repos/asf/ignite/blob/c050b4ce/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableUtils.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/c050b4ce/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/BinaryObjectBuilderImpl.java
----------------------------------------------------------------------
diff --cc modules/core/src/main/java/org/apache/ignite/internal/portable/builder/BinaryObjectBuilderImpl.java
index e6a68c1,0000000..a809d3c
mode 100644,000000..100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/BinaryObjectBuilderImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/BinaryObjectBuilderImpl.java
@@@ -1,551 -1,0 +1,566 @@@
+/*
+ * 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.portable.builder;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import org.apache.ignite.binary.BinaryObject;
+import org.apache.ignite.binary.BinaryObjectBuilder;
+import org.apache.ignite.binary.BinaryObjectException;
+import org.apache.ignite.binary.BinaryInvalidTypeException;
+import org.apache.ignite.binary.BinaryType;
+import org.apache.ignite.internal.portable.BinaryObjectImpl;
+import org.apache.ignite.internal.portable.BinaryObjectOffheapImpl;
+import org.apache.ignite.internal.portable.BinaryWriterExImpl;
+import org.apache.ignite.internal.portable.PortableContext;
+import org.apache.ignite.internal.portable.PortableUtils;
+import org.apache.ignite.internal.processors.cache.portable.CacheObjectPortableProcessorImpl;
+import org.apache.ignite.internal.util.GridArgumentCheck;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteBiTuple;
+import org.jetbrains.annotations.Nullable;
+
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.DFLT_HDR_LEN;
++import static org.apache.ignite.internal.portable.GridPortableMarshaller.FLAGS_POS;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.HASH_CODE_POS;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.PROTO_VER_POS;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.TYPE_ID_POS;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.UNREGISTERED_TYPE_ID;
+
+/**
+ *
+ */
+public class BinaryObjectBuilderImpl implements BinaryObjectBuilder {
+ /** */
+ private static final Object REMOVED_FIELD_MARKER = new Object();
+
+ /** */
+ private final PortableContext ctx;
+
+ /** */
+ private final int typeId;
+
+ /** May be null. */
+ private String typeName;
+
+ /** May be null. */
+ private String clsNameToWrite;
+
+ /** */
+ private boolean registeredType = true;
+
+ /** */
+ private Map<String, Object> assignedVals;
+
+ /** */
+ private Map<Integer, Object> readCache;
+
+ /** Position of object in source array, or -1 if object is not created from PortableObject. */
+ private final int start;
+
++ /** Flags. */
++ private final short flags;
++
+ /** Total header length */
+ private final int hdrLen;
+
- /**
- * Context of PortableObject reading process. Or {@code null} if object is not created from PortableObject.
- */
++ /** Context of PortableObject reading process. Or {@code null} if object is not created from PortableObject. */
+ private final PortableBuilderReader reader;
+
+ /** */
+ private int hashCode;
+
+ /**
+ * @param clsName Class name.
+ * @param ctx Portable context.
+ */
+ public BinaryObjectBuilderImpl(PortableContext ctx, String clsName) {
+ this(ctx, ctx.typeId(clsName), PortableContext.typeName(clsName));
+ }
+
+ /**
+ * @param typeId Type ID.
+ * @param ctx Portable context.
+ */
+ public BinaryObjectBuilderImpl(PortableContext ctx, int typeId) {
+ this(ctx, typeId, null);
+ }
+
+ /**
+ * @param typeName Type name.
+ * @param ctx Context.
+ * @param typeId Type id.
+ */
+ public BinaryObjectBuilderImpl(PortableContext ctx, int typeId, String typeName) {
+ this.typeId = typeId;
+ this.typeName = typeName;
+ this.ctx = ctx;
+
+ start = -1;
++ flags = -1;
+ reader = null;
+ hdrLen = DFLT_HDR_LEN;
+
+ readCache = Collections.emptyMap();
+ }
+
+ /**
+ * @param obj Object to wrap.
+ */
+ public BinaryObjectBuilderImpl(BinaryObjectImpl obj) {
+ this(new PortableBuilderReader(obj), obj.start());
+
+ reader.registerObject(this);
+ }
+
+ /**
+ * @param reader ctx
+ * @param start Start.
+ */
+ BinaryObjectBuilderImpl(PortableBuilderReader reader, int start) {
+ this.reader = reader;
+ this.start = start;
++ this.flags = reader.readShortPositioned(start + FLAGS_POS);
+
+ byte ver = reader.readBytePositioned(start + PROTO_VER_POS);
+
+ PortableUtils.checkProtocolVersion(ver);
+
+ int typeId = reader.readIntPositioned(start + TYPE_ID_POS);
+ ctx = reader.portableContext();
+ hashCode = reader.readIntPositioned(start + HASH_CODE_POS);
+
+ if (typeId == UNREGISTERED_TYPE_ID) {
+ int mark = reader.position();
+
+ reader.position(start + DFLT_HDR_LEN);
+
+ clsNameToWrite = reader.readString();
+
+ Class cls;
+
+ try {
+ // TODO: IGNITE-1272 - Is class loader needed here?
+ cls = U.forName(clsNameToWrite, null);
+ }
+ catch (ClassNotFoundException e) {
+ throw new BinaryInvalidTypeException("Failed to load the class: " + clsNameToWrite, e);
+ }
+
+ this.typeId = ctx.descriptorForClass(cls).typeId();
+
+ registeredType = false;
+
+ hdrLen = reader.position() - mark;
+
+ reader.position(mark);
+ }
+ else {
+ this.typeId = typeId;
+ hdrLen = DFLT_HDR_LEN;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public BinaryObject build() {
+ try (BinaryWriterExImpl writer = new BinaryWriterExImpl(ctx, typeId, false)) {
+
+ PortableBuilderSerializer serializationCtx = new PortableBuilderSerializer();
+
+ serializationCtx.registerObjectWriting(this, 0);
+
+ serializeTo(writer, serializationCtx);
+
+ byte[] arr = writer.array();
+
+ return new BinaryObjectImpl(ctx, arr, 0);
+ }
+ }
+
+ /**
+ * @param writer Writer.
+ * @param serializer Serializer.
+ */
+ void serializeTo(BinaryWriterExImpl writer, PortableBuilderSerializer serializer) {
- PortableUtils.writeHeader(writer,
- true,
- registeredType ? typeId : UNREGISTERED_TYPE_ID,
- hashCode,
- registeredType ? null : clsNameToWrite);
++ try {
++ PortableUtils.writeHeader(writer,
++ true,
++ registeredType ? typeId : UNREGISTERED_TYPE_ID,
++ hashCode,
++ registeredType ? null : clsNameToWrite);
+
- Set<Integer> remainsFlds = null;
++ Set<Integer> remainsFlds = null;
+
- if (reader != null) {
- Map<Integer, Object> assignedFldsById;
++ if (reader != null) {
++ Map<Integer, Object> assignedFldsById;
+
- if (assignedVals != null) {
- assignedFldsById = U.newHashMap(assignedVals.size());
++ if (assignedVals != null) {
++ assignedFldsById = U.newHashMap(assignedVals.size());
+
- for (Map.Entry<String, Object> entry : assignedVals.entrySet()) {
- int fldId = ctx.fieldId(typeId, entry.getKey());
++ for (Map.Entry<String, Object> entry : assignedVals.entrySet()) {
++ int fldId = ctx.fieldId(typeId, entry.getKey());
+
- assignedFldsById.put(fldId, entry.getValue());
- }
++ assignedFldsById.put(fldId, entry.getValue());
++ }
+
- remainsFlds = assignedFldsById.keySet();
- }
- else
- assignedFldsById = Collections.emptyMap();
++ remainsFlds = assignedFldsById.keySet();
++ } else
++ assignedFldsById = Collections.emptyMap();
+
- // Get footer details.
- IgniteBiTuple<Integer, Integer> footer = PortableUtils.footerAbsolute(reader, start);
++ // Get footer details.
++ int fieldOffsetSize = PortableUtils.fieldOffsetSize(flags);
+
- int footerPos = footer.get1();
- int footerEnd = footer.get2();
++ IgniteBiTuple<Integer, Integer> footer = PortableUtils.footerAbsolute(reader, start, fieldOffsetSize);
+
- // Get raw position.
- int rawPos = PortableUtils.rawOffsetAbsolute(reader, start);
++ int footerPos = footer.get1();
++ int footerEnd = footer.get2();
+
- // Position reader on data.
- reader.position(start + hdrLen);
++ // Get raw position.
++ int rawPos = PortableUtils.rawOffsetAbsolute(reader, start, fieldOffsetSize);
+
- while (reader.position() < rawPos) {
- int fieldId = reader.readIntPositioned(footerPos);
- int fieldLen = fieldPositionAndLength(footerPos, footerEnd, rawPos).get2();
++ // Position reader on data.
++ reader.position(start + hdrLen);
+
- footerPos += 8;
++ while (reader.position() + 4 < rawPos) {
++ int fieldId = reader.readIntPositioned(footerPos);
++ int fieldLen = fieldPositionAndLength(footerPos, footerEnd, rawPos, fieldOffsetSize).get2();
+
- if (assignedFldsById.containsKey(fieldId)) {
- Object assignedVal = assignedFldsById.remove(fieldId);
++ footerPos += 4 + fieldOffsetSize;
+
- reader.skip(fieldLen);
++ if (assignedFldsById.containsKey(fieldId)) {
++ Object assignedVal = assignedFldsById.remove(fieldId);
+
- if (assignedVal != REMOVED_FIELD_MARKER) {
- writer.writeFieldId(fieldId);
++ reader.skip(fieldLen);
+
- serializer.writeValue(writer, assignedVal);
- }
- }
- else {
- int type = fieldLen != 0 ? reader.readByte(0) : 0;
++ if (assignedVal != REMOVED_FIELD_MARKER) {
++ writer.writeFieldId(fieldId);
+
- if (fieldLen != 0 && !PortableUtils.isPlainArrayType(type) && PortableUtils.isPlainType(type)) {
- writer.writeFieldId(fieldId);
- writer.write(reader.array(), reader.position(), fieldLen);
++ serializer.writeValue(writer, assignedVal);
++ }
++ } else {
++ int type = fieldLen != 0 ? reader.readByte(0) : 0;
+
- reader.skip(fieldLen);
- }
- else {
- writer.writeFieldId(fieldId);
++ if (fieldLen != 0 && !PortableUtils.isPlainArrayType(type) && PortableUtils.isPlainType(type)) {
++ writer.writeFieldId(fieldId);
++ writer.write(reader.array(), reader.position(), fieldLen);
+
- Object val;
++ reader.skip(fieldLen);
++ } else {
++ writer.writeFieldId(fieldId);
+
- if (fieldLen == 0)
- val = null;
- else if (readCache == null) {
- int savedPos = reader.position();
++ Object val;
+
- val = reader.parseValue();
++ if (fieldLen == 0)
++ val = null;
++ else if (readCache == null) {
++ int savedPos = reader.position();
+
- assert reader.position() == savedPos + fieldLen;
- }
- else {
- val = readCache.get(fieldId);
++ val = reader.parseValue();
+
- reader.skip(fieldLen);
- }
++ assert reader.position() == savedPos + fieldLen;
++ } else {
++ val = readCache.get(fieldId);
++
++ reader.skip(fieldLen);
++ }
+
- serializer.writeValue(writer, val);
++ serializer.writeValue(writer, val);
++ }
+ }
+ }
+ }
- }
-
- if (assignedVals != null && (remainsFlds == null || !remainsFlds.isEmpty())) {
- boolean metadataEnabled = ctx.isMetaDataEnabled(typeId);
+
- BinaryType metadata = null;
++ if (assignedVals != null && (remainsFlds == null || !remainsFlds.isEmpty())) {
++ boolean metadataEnabled = ctx.isMetaDataEnabled(typeId);
+
- if (metadataEnabled)
- metadata = ctx.metaData(typeId);
++ BinaryType metadata = null;
+
- Map<String, String> newFldsMetadata = null;
++ if (metadataEnabled)
++ metadata = ctx.metaData(typeId);
+
- for (Map.Entry<String, Object> entry : assignedVals.entrySet()) {
- Object val = entry.getValue();
++ Map<String, String> newFldsMetadata = null;
+
- if (val == REMOVED_FIELD_MARKER)
- continue;
-
- String name = entry.getKey();
++ for (Map.Entry<String, Object> entry : assignedVals.entrySet()) {
++ Object val = entry.getValue();
+
- int fldId = ctx.fieldId(typeId, name);
++ if (val == REMOVED_FIELD_MARKER)
++ continue;
+
- if (remainsFlds != null && !remainsFlds.contains(fldId))
- continue;
++ String name = entry.getKey();
+
- writer.writeFieldId(fldId);
++ int fldId = ctx.fieldId(typeId, name);
+
- serializer.writeValue(writer, val);
++ if (remainsFlds != null && !remainsFlds.contains(fldId))
++ continue;
+
- if (metadataEnabled) {
- String oldFldTypeName = metadata == null ? null : metadata.fieldTypeName(name);
++ writer.writeFieldId(fldId);
+
- String newFldTypeName;
++ serializer.writeValue(writer, val);
+
- if (val instanceof PortableValueWithType)
- newFldTypeName = ((PortableValueWithType)val).typeName();
- else {
- byte type = PortableUtils.typeByClass(val.getClass());
++ if (metadataEnabled) {
++ String oldFldTypeName = metadata == null ? null : metadata.fieldTypeName(name);
+
- newFldTypeName = CacheObjectPortableProcessorImpl.fieldTypeName(type);
- }
++ String newFldTypeName;
+
- if (oldFldTypeName == null) {
- // It's a new field, we have to add it to metadata.
++ if (val instanceof PortableValueWithType)
++ newFldTypeName = ((PortableValueWithType) val).typeName();
++ else {
++ byte type = PortableUtils.typeByClass(val.getClass());
+
- if (newFldsMetadata == null)
- newFldsMetadata = new HashMap<>();
++ newFldTypeName = CacheObjectPortableProcessorImpl.fieldTypeName(type);
++ }
+
- newFldsMetadata.put(name, newFldTypeName);
- }
- else {
- if (!"Object".equals(oldFldTypeName) && !oldFldTypeName.equals(newFldTypeName)) {
- throw new BinaryObjectException(
- "Wrong value has been set [" +
- "typeName=" + (typeName == null ? metadata.typeName() : typeName) +
- ", fieldName=" + name +
- ", fieldType=" + oldFldTypeName +
- ", assignedValueType=" + newFldTypeName +
- ", assignedValue=" + (((PortableValueWithType)val).value()) + ']'
- );
++ if (oldFldTypeName == null) {
++ // It's a new field, we have to add it to metadata.
++
++ if (newFldsMetadata == null)
++ newFldsMetadata = new HashMap<>();
++
++ newFldsMetadata.put(name, newFldTypeName);
++ } else {
++ if (!"Object".equals(oldFldTypeName) && !oldFldTypeName.equals(newFldTypeName)) {
++ throw new BinaryObjectException(
++ "Wrong value has been set [" +
++ "typeName=" + (typeName == null ? metadata.typeName() : typeName) +
++ ", fieldName=" + name +
++ ", fieldType=" + oldFldTypeName +
++ ", assignedValueType=" + newFldTypeName +
++ ", assignedValue=" + (((PortableValueWithType) val).value()) + ']'
++ );
++ }
+ }
+ }
+ }
- }
+
- if (newFldsMetadata != null) {
- String typeName = this.typeName;
++ if (newFldsMetadata != null) {
++ String typeName = this.typeName;
+
- if (typeName == null)
- typeName = metadata.typeName();
++ if (typeName == null)
++ typeName = metadata.typeName();
+
- ctx.updateMetaData(typeId, typeName, newFldsMetadata);
++ ctx.updateMetaData(typeId, typeName, newFldsMetadata);
++ }
+ }
- }
+
- if (reader != null) {
- // Write raw data if any.
- int rawOff = PortableUtils.rawOffsetAbsolute(reader, start);
- int footerStart = PortableUtils.footerStartAbsolute(reader, start);
++ if (reader != null) {
++ // Write raw data if any.
++ int fieldOffsetSize = PortableUtils.fieldOffsetSize(flags);
++
++ int rawOff = PortableUtils.rawOffsetAbsolute(reader, start, fieldOffsetSize);
++ int footerStart = PortableUtils.footerStartAbsolute(reader, start);
+
- if (rawOff < footerStart) {
- writer.rawWriter();
++ if (rawOff < footerStart) {
++ writer.rawWriter();
+
- writer.write(reader.array(), rawOff, footerStart - rawOff);
++ writer.write(reader.array(), rawOff, footerStart - rawOff);
++ }
++
++ // Shift reader to the end of the object.
++ reader.position(start + PortableUtils.length(reader, start));
+ }
+
- // Shift reader to the end of the object.
- reader.position(start + PortableUtils.length(reader, start));
++ writer.postWrite(true);
++ }
++ finally {
++ writer.popSchema();
+ }
-
- writer.postWrite(true);
+ }
+
+ /** {@inheritDoc} */
+ @Override public BinaryObjectBuilderImpl hashCode(int hashCode) {
+ this.hashCode = hashCode;
+
+ return this;
+ }
+
+ /**
+ * Get field position and length.
+ *
+ * @param footerPos Field position inside the footer (absolute).
+ * @param footerEnd Footer end (absolute).
+ * @param rawPos Raw data position (absolute).
++ * @param fieldOffsetSize Size of field's offset.
+ * @return Tuple with field position and length.
+ */
- private IgniteBiTuple<Integer, Integer> fieldPositionAndLength(int footerPos, int footerEnd, int rawPos) {
- int fieldOffset = reader.readIntPositioned(footerPos + 4);
++ private IgniteBiTuple<Integer, Integer> fieldPositionAndLength(int footerPos, int footerEnd, int rawPos,
++ int fieldOffsetSize) {
++ // Get field offset first.
++ int fieldOffset = PortableUtils.fieldOffsetRelative(reader, footerPos + 4, fieldOffsetSize);
+ int fieldPos = start + fieldOffset;
+
+ // Get field length.
+ int fieldLen;
+
- if (footerPos + 8 == footerEnd)
++ if (footerPos + 4 + fieldOffsetSize == footerEnd)
+ // This is the last field, compare to raw offset.
+ fieldLen = rawPos - fieldPos;
+ else {
+ // Field is somewhere in the middle, get difference with the next offset.
- int nextFieldOffset = reader.readIntPositioned(footerPos + 8 + 4);
++ int nextFieldOffset = PortableUtils.fieldOffsetRelative(reader, footerPos + 4 + fieldOffsetSize + 4,
++ fieldOffsetSize);
+
+ fieldLen = nextFieldOffset - fieldOffset;
+ }
+
+ return F.t(fieldPos, fieldLen);
+ }
+
+ /**
+ * Initialize read cache if needed.
+ */
+ private void ensureReadCacheInit() {
+ if (readCache == null) {
++ int fieldOffsetSize = PortableUtils.fieldOffsetSize(flags);
++
+ Map<Integer, Object> readCache = new HashMap<>();
+
- IgniteBiTuple<Integer, Integer> footer = PortableUtils.footerAbsolute(reader, start);
++ IgniteBiTuple<Integer, Integer> footer = PortableUtils.footerAbsolute(reader, start, fieldOffsetSize);
+
+ int footerPos = footer.get1();
+ int footerEnd = footer.get2();
+
- int rawPos = PortableUtils.rawOffsetAbsolute(reader, start);
++ int rawPos = PortableUtils.rawOffsetAbsolute(reader, start, fieldOffsetSize);
+
- while (footerPos < footerEnd) {
++ while (footerPos + 4 < footerEnd) {
+ int fieldId = reader.readIntPositioned(footerPos);
+
- IgniteBiTuple<Integer, Integer> posAndLen = fieldPositionAndLength(footerPos, footerEnd, rawPos);
++ IgniteBiTuple<Integer, Integer> posAndLen =
++ fieldPositionAndLength(footerPos, footerEnd, rawPos, fieldOffsetSize);
+
+ Object val = reader.getValueQuickly(posAndLen.get1(), posAndLen.get2());
+
+ readCache.put(fieldId, val);
+
+ // Shift current footer position.
- footerPos += 8;
++ footerPos += 4 + fieldOffsetSize;
+ }
+
+ this.readCache = readCache;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @SuppressWarnings("unchecked")
+ @Override public <T> T getField(String name) {
+ Object val;
+
+ if (assignedVals != null && assignedVals.containsKey(name)) {
+ val = assignedVals.get(name);
+
+ if (val == REMOVED_FIELD_MARKER)
+ return null;
+ }
+ else {
+ ensureReadCacheInit();
+
+ int fldId = ctx.fieldId(typeId, name);
+
+ val = readCache.get(fldId);
+ }
+
+ return (T)PortableUtils.unwrapLazy(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public BinaryObjectBuilder setField(String name, Object val) {
+ GridArgumentCheck.notNull(val, name);
+
+ if (assignedVals == null)
+ assignedVals = new LinkedHashMap<>();
+
+ Object oldVal = assignedVals.put(name, val);
+
+ if (oldVal instanceof PortableValueWithType) {
+ ((PortableValueWithType)oldVal).value(val);
+
+ assignedVals.put(name, oldVal);
+ }
+
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ @Override public <T> BinaryObjectBuilder setField(String name, @Nullable T val, Class<? super T> type) {
+ if (assignedVals == null)
+ assignedVals = new LinkedHashMap<>();
+
+ //int fldId = ctx.fieldId(typeId, fldName);
+
+ assignedVals.put(name, new PortableValueWithType(PortableUtils.typeByClass(type), val));
+
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ @Override public BinaryObjectBuilder setField(String name, @Nullable BinaryObjectBuilder builder) {
+ if (builder == null)
+ return setField(name, null, Object.class);
+ else
+ return setField(name, (Object)builder);
+ }
+
+ /**
+ * Removes field from portable object.
+ *
+ * @param name Field name.
+ * @return {@code this} instance for chaining.
+ */
+ @Override public BinaryObjectBuilderImpl removeField(String name) {
+ if (assignedVals == null)
+ assignedVals = new LinkedHashMap<>();
+
+ assignedVals.put(name, REMOVED_FIELD_MARKER);
+
+ return this;
+ }
+
+ /**
+ * Creates builder initialized by specified portable object.
+ *
+ * @param obj Portable object to initialize builder.
+ * @return New builder.
+ */
+ public static BinaryObjectBuilderImpl wrap(BinaryObject obj) {
+ BinaryObjectImpl heapObj;
+
+ if (obj instanceof BinaryObjectOffheapImpl)
+ heapObj = (BinaryObjectImpl)((BinaryObjectOffheapImpl)obj).heapCopy();
+ else
+ heapObj = (BinaryObjectImpl)obj;
+
+ return new BinaryObjectBuilderImpl(heapObj);
+ }
+
+ /**
+ * @return Object start position in source array.
+ */
+ int start() {
+ return start;
+ }
+
+ /**
+ * @return Object type id.
+ */
+ public int typeId() {
+ return typeId;
+ }
+}