You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2015/08/25 09:14:16 UTC
[16/18] ignite git commit: ignite-1258: portable objects API support
in Ignite
http://git-wip-us.apache.org/repos/asf/ignite/blob/878dcd92/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableBuilderReader.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableBuilderReader.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableBuilderReader.java
new file mode 100644
index 0000000..3e0286f
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableBuilderReader.java
@@ -0,0 +1,775 @@
+/*
+ * 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.portable.*;
+
+import java.sql.*;
+import java.util.Date;
+import java.util.*;
+
+import static java.nio.charset.StandardCharsets.*;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.*;
+
+/**
+ *
+ */
+class PortableBuilderReader {
+ /** */
+ private static final PortablePrimitives PRIM = PortablePrimitives.get();
+
+ /** */
+ private final Map<Integer, PortableBuilderImpl> objMap = new HashMap<>();
+
+ /** */
+ private final PortableContext ctx;
+
+ /** */
+ private final PortableReaderExImpl reader;
+
+ /** */
+ private byte[] arr;
+
+ /** */
+ private int pos;
+
+ /**
+ * @param objImpl Portable object
+ */
+ PortableBuilderReader(PortableObjectImpl objImpl) {
+ ctx = objImpl.context();
+ arr = objImpl.array();
+ pos = objImpl.start();
+
+ // TODO: IGNITE-1272 - Is class loader needed here?
+ reader = new PortableReaderExImpl(portableContext(), arr, pos, null);
+ }
+
+ /**
+ * @return Portable context.
+ */
+ public PortableContext portableContext() {
+ return ctx;
+ }
+
+ /**
+ * @param obj Mutable portable object.
+ */
+ public void registerObject(PortableBuilderImpl obj) {
+ objMap.put(obj.start(), obj);
+ }
+
+ /**
+ * @return Read int value.
+ */
+ public int readInt() {
+ int res = readInt(0);
+
+ pos += 4;
+
+ return res;
+ }
+
+ /**
+ * @return Read int value.
+ */
+ public byte readByte() {
+ return arr[pos++];
+ }
+
+ /**
+ * @return Read boolean value.
+ */
+ public boolean readBoolean() {
+ return readByte() == 1;
+ }
+
+ /**
+ * @return Read int value.
+ */
+ public byte readByte(int off) {
+ return arr[pos + off];
+ }
+
+ /**
+ * @param off Offset related to {@link #pos}
+ * @return Read int value.
+ */
+ public int readInt(int off) {
+ return PRIM.readInt(arr, pos + off);
+ }
+
+ /**
+ * @param pos Position in the source array.
+ * @return Read int value.
+ */
+ public int readIntAbsolute(int pos) {
+ return PRIM.readInt(arr, pos);
+ }
+
+ /**
+ * @return Read length of array.
+ */
+ public int readLength() {
+ return PRIM.readInt(arr, pos);
+ }
+
+ /**
+ * Read string length.
+ *
+ * @return String length.
+ */
+ public int readStringLength() {
+ boolean utf = PRIM.readBoolean(arr, pos);
+
+ int arrLen = PRIM.readInt(arr, pos + 1);
+
+ return 1 + (utf ? arrLen : arrLen << 1);
+ }
+
+ /**
+ * Reads string.
+ *
+ * @return String.
+ */
+ public String readString() {
+ byte flag = readByte();
+
+ if (flag == NULL)
+ return null;
+
+ if (flag != STRING)
+ throw new PortableException("Failed to deserialize String.");
+
+ boolean convert = readBoolean();
+ int len = readInt();
+
+ String str;
+
+ if (convert) {
+ str = new String(arr, pos, len, UTF_8);
+
+ pos += len;
+ }
+ else {
+ str = String.valueOf(PRIM.readCharArray(arr, pos, len));
+
+ pos += len << 1;
+ }
+
+ return str;
+ }
+
+ /**
+ *
+ */
+ public void skipValue() {
+ byte type = arr[pos++];
+
+ int len;
+
+ switch (type) {
+ case GridPortableMarshaller.NULL:
+ return;
+
+ case GridPortableMarshaller.OBJ:
+ pos += readInt(GridPortableMarshaller.TOTAL_LEN_POS - 1) - 1;
+
+ return;
+
+ case GridPortableMarshaller.BOOLEAN:
+ case GridPortableMarshaller.BYTE:
+ len = 1;
+ break;
+
+ case GridPortableMarshaller.CHAR:
+ case GridPortableMarshaller.SHORT:
+ len = 2;
+
+ break;
+
+ case GridPortableMarshaller.HANDLE:
+ case GridPortableMarshaller.FLOAT:
+ case GridPortableMarshaller.INT:
+ len = 4;
+
+ break;
+
+ case GridPortableMarshaller.ENUM:
+ //skipping type id and ordinal value
+ len = 8;
+
+ break;
+
+ case GridPortableMarshaller.LONG:
+ case GridPortableMarshaller.DOUBLE:
+ len = 8;
+
+ break;
+
+ case GridPortableMarshaller.BYTE_ARR:
+ case GridPortableMarshaller.BOOLEAN_ARR:
+ len = 4 + readLength();
+
+ break;
+
+ case GridPortableMarshaller.STRING:
+ len = 4 + readStringLength();
+
+ break;
+
+ case GridPortableMarshaller.DECIMAL:
+ len = /** scale */ 4 + /** mag len */ 4 + /** mag bytes count */ readInt(4);
+
+ break;
+
+ case GridPortableMarshaller.UUID:
+ len = 8 + 8;
+
+ break;
+
+ case GridPortableMarshaller.DATE:
+ len = 8 + 4;
+
+ break;
+
+ case GridPortableMarshaller.CHAR_ARR:
+ case GridPortableMarshaller.SHORT_ARR:
+ len = 4 + readLength() * 2;
+
+ break;
+
+ case GridPortableMarshaller.INT_ARR:
+ case GridPortableMarshaller.FLOAT_ARR:
+ len = 4 + readLength() * 4;
+
+ break;
+
+ case GridPortableMarshaller.LONG_ARR:
+ case GridPortableMarshaller.DOUBLE_ARR:
+ len = 4 + readLength() * 8;
+
+ break;
+
+ case GridPortableMarshaller.DECIMAL_ARR:
+ case GridPortableMarshaller.DATE_ARR:
+ case GridPortableMarshaller.OBJ_ARR:
+ case GridPortableMarshaller.ENUM_ARR:
+ case GridPortableMarshaller.UUID_ARR:
+ case GridPortableMarshaller.STRING_ARR: {
+ int size = readInt();
+
+ for (int i = 0; i < size; i++)
+ skipValue();
+
+ return;
+ }
+
+ case GridPortableMarshaller.COL: {
+ int size = readInt();
+
+ pos++; // skip collection type
+
+ for (int i = 0; i < size; i++)
+ skipValue();
+
+ return;
+ }
+
+ case GridPortableMarshaller.MAP: {
+ int size = readInt();
+
+ pos++; // skip collection type
+
+ for (int i = 0; i < size; i++) {
+ skipValue(); // skip key.
+ skipValue(); // skip value.
+ }
+
+ return;
+ }
+
+ case GridPortableMarshaller.MAP_ENTRY:
+ skipValue();
+ skipValue();
+
+ return;
+
+ case GridPortableMarshaller.PORTABLE_OBJ:
+ len = readInt() + 4;
+
+ break;
+
+ default:
+ throw new PortableException("Invalid flag value: " + type);
+ }
+
+ pos += len;
+ }
+
+ /**
+ * @param pos Position.
+ * @param len Length.
+ * @return Object.
+ */
+ public Object getValueQuickly(int pos, int len) {
+ byte type = arr[pos];
+
+ switch (type) {
+ case GridPortableMarshaller.NULL:
+ return null;
+
+ case GridPortableMarshaller.HANDLE: {
+ int objStart = pos - readIntAbsolute(pos + 1);
+
+ PortableBuilderImpl res = objMap.get(objStart);
+
+ if (res == null) {
+ res = new PortableBuilderImpl(this, objStart);
+
+ objMap.put(objStart, res);
+ }
+
+ return res;
+ }
+
+ case GridPortableMarshaller.OBJ: {
+ PortableBuilderImpl res = objMap.get(pos);
+
+ if (res == null) {
+ res = new PortableBuilderImpl(this, pos);
+
+ objMap.put(pos, res);
+ }
+
+ return res;
+ }
+
+ case GridPortableMarshaller.BYTE:
+ return arr[pos + 1];
+
+ case GridPortableMarshaller.SHORT:
+ return PRIM.readShort(arr, pos + 1);
+
+ case GridPortableMarshaller.INT:
+ return PRIM.readInt(arr, pos + 1);
+
+ case GridPortableMarshaller.LONG:
+ return PRIM.readLong(arr, pos + 1);
+
+ case GridPortableMarshaller.FLOAT:
+ return PRIM.readFloat(arr, pos + 1);
+
+ case GridPortableMarshaller.DOUBLE:
+ return PRIM.readDouble(arr, pos + 1);
+
+ case GridPortableMarshaller.CHAR:
+ return PRIM.readChar(arr, pos + 1);
+
+ case GridPortableMarshaller.BOOLEAN:
+ return arr[pos + 1] != 0;
+
+ case GridPortableMarshaller.DECIMAL:
+ case GridPortableMarshaller.STRING:
+ case GridPortableMarshaller.UUID:
+ case GridPortableMarshaller.DATE:
+ case GridPortableMarshaller.BYTE_ARR:
+ case GridPortableMarshaller.SHORT_ARR:
+ case GridPortableMarshaller.INT_ARR:
+ case GridPortableMarshaller.LONG_ARR:
+ case GridPortableMarshaller.FLOAT_ARR:
+ case GridPortableMarshaller.DOUBLE_ARR:
+ case GridPortableMarshaller.CHAR_ARR:
+ case GridPortableMarshaller.BOOLEAN_ARR:
+ case GridPortableMarshaller.DECIMAL_ARR:
+ case GridPortableMarshaller.DATE_ARR:
+ case GridPortableMarshaller.UUID_ARR:
+ case GridPortableMarshaller.STRING_ARR:
+ return new PortablePlainLazyValue(this, pos, len);
+
+ case GridPortableMarshaller.COL:
+ case GridPortableMarshaller.OBJ_ARR:
+ case GridPortableMarshaller.MAP:
+ case GridPortableMarshaller.ENUM_ARR:
+ case GridPortableMarshaller.MAP_ENTRY:
+ return new LazyCollection(pos);
+
+ case GridPortableMarshaller.ENUM: {
+ if (len == 1) {
+ assert readByte(pos) == GridPortableMarshaller.NULL;
+
+ return null;
+ }
+
+ int mark = position();
+ position(pos + 1);
+
+ PortableBuilderEnum builderEnum = new PortableBuilderEnum(this);
+
+ position(mark);
+
+ return builderEnum;
+ }
+
+ case GridPortableMarshaller.PORTABLE_OBJ: {
+ int size = readIntAbsolute(pos + 1);
+
+ int start = readIntAbsolute(pos + 4 + size);
+
+ PortableObjectImpl portableObj = new PortableObjectImpl(ctx, arr, pos + 4 + start);
+
+ return new PortablePlainPortableObject(portableObj);
+ }
+
+ default:
+ throw new PortableException("Invalid flag value: " + type);
+ }
+ }
+
+ /**
+ * @return Parsed value.
+ */
+ public Object parseValue() {
+ int valPos = pos;
+
+ byte type = arr[pos++];
+
+ int plainLazyValLen;
+
+ switch (type) {
+ case GridPortableMarshaller.NULL:
+ return null;
+
+ case GridPortableMarshaller.HANDLE: {
+ int objStart = pos - 1 - readInt();
+
+ PortableBuilderImpl res = objMap.get(objStart);
+
+ if (res == null) {
+ res = new PortableBuilderImpl(this, objStart);
+
+ objMap.put(objStart, res);
+ }
+
+ return res;
+ }
+
+ case GridPortableMarshaller.OBJ: {
+ pos--;
+
+ PortableBuilderImpl res = objMap.get(pos);
+
+ if (res == null) {
+ res = new PortableBuilderImpl(this, pos);
+
+ objMap.put(pos, res);
+ }
+
+ pos += readInt(GridPortableMarshaller.TOTAL_LEN_POS);
+
+ return res;
+ }
+
+ case GridPortableMarshaller.BYTE:
+ return arr[pos++];
+
+ case GridPortableMarshaller.SHORT: {
+ Object res = PRIM.readShort(arr, pos);
+ pos += 2;
+ return res;
+ }
+
+ case GridPortableMarshaller.INT:
+ return readInt();
+
+ case GridPortableMarshaller.LONG:
+ plainLazyValLen = 8;
+
+ break;
+
+ case GridPortableMarshaller.FLOAT:
+ plainLazyValLen = 4;
+
+ break;
+
+ case GridPortableMarshaller.DOUBLE:
+ plainLazyValLen = 8;
+
+ break;
+
+ case GridPortableMarshaller.CHAR:
+ plainLazyValLen = 2;
+
+ break;
+
+ case GridPortableMarshaller.BOOLEAN:
+ return arr[pos++] != 0;
+
+ case GridPortableMarshaller.DECIMAL:
+ plainLazyValLen = /** scale */ 4 + /** mag len */ 4 + /** mag bytes count */ readInt(4);
+
+ break;
+
+ case GridPortableMarshaller.STRING:
+ plainLazyValLen = 4 + readStringLength();
+
+ break;
+
+ case GridPortableMarshaller.UUID:
+ plainLazyValLen = 8 + 8;
+
+ break;
+
+ case GridPortableMarshaller.DATE:
+ plainLazyValLen = 8 + 4;
+
+ break;
+
+ case GridPortableMarshaller.BYTE_ARR:
+ plainLazyValLen = 4 + readLength();
+
+ break;
+
+ case GridPortableMarshaller.SHORT_ARR:
+ plainLazyValLen = 4 + readLength() * 2;
+
+ break;
+
+ case GridPortableMarshaller.INT_ARR:
+ plainLazyValLen = 4 + readLength() * 4;
+
+ break;
+
+ case GridPortableMarshaller.LONG_ARR:
+ plainLazyValLen = 4 + readLength() * 8;
+
+ break;
+
+ case GridPortableMarshaller.FLOAT_ARR:
+ plainLazyValLen = 4 + readLength() * 4;
+
+ break;
+
+ case GridPortableMarshaller.DOUBLE_ARR:
+ plainLazyValLen = 4 + readLength() * 8;
+
+ break;
+
+ case GridPortableMarshaller.CHAR_ARR:
+ plainLazyValLen = 4 + readLength() * 2;
+
+ break;
+
+ case GridPortableMarshaller.BOOLEAN_ARR:
+ plainLazyValLen = 4 + readLength();
+
+ break;
+
+ case GridPortableMarshaller.OBJ_ARR:
+ return new PortableObjectArrayLazyValue(this);
+
+ case GridPortableMarshaller.DATE_ARR: {
+ int size = readInt();
+
+ Date[] res = new Date[size];
+
+ for (int i = 0; i < res.length; i++) {
+ byte flag = arr[pos++];
+
+ if (flag == GridPortableMarshaller.NULL) continue;
+
+ if (flag != GridPortableMarshaller.DATE)
+ throw new PortableException("Invalid flag value: " + flag);
+
+ long time = PRIM.readLong(arr, pos);
+
+ pos += 8;
+
+ if (ctx.isUseTimestamp()) {
+ Timestamp ts = new Timestamp(time);
+
+ ts.setNanos(ts.getNanos() + readInt());
+
+ res[i] = ts;
+ }
+ else {
+ res[i] = new Date(time);
+
+ pos += 4;
+ }
+ }
+
+ return res;
+ }
+
+ case GridPortableMarshaller.UUID_ARR:
+ case GridPortableMarshaller.STRING_ARR:
+ case GridPortableMarshaller.DECIMAL_ARR: {
+ int size = readInt();
+
+ for (int i = 0; i < size; i++) {
+ byte flag = arr[pos++];
+
+ if (flag == GridPortableMarshaller.UUID)
+ pos += 8 + 8;
+ else if (flag == GridPortableMarshaller.STRING)
+ pos += 4 + readStringLength();
+ else if (flag == GridPortableMarshaller.DECIMAL)
+ pos += 4 + readLength();
+ else
+ assert flag == GridPortableMarshaller.NULL;
+ }
+
+ return new PortablePlainLazyValue(this, valPos, pos - valPos);
+ }
+
+ case GridPortableMarshaller.COL: {
+ int size = readInt();
+ byte colType = arr[pos++];
+
+ switch (colType) {
+ case GridPortableMarshaller.USER_COL:
+ case GridPortableMarshaller.ARR_LIST:
+ return new PortableLazyArrayList(this, size);
+
+ case GridPortableMarshaller.LINKED_LIST:
+ return new PortableLazyLinkedList(this, size);
+
+ case GridPortableMarshaller.HASH_SET:
+ case GridPortableMarshaller.LINKED_HASH_SET:
+ case GridPortableMarshaller.TREE_SET:
+ case GridPortableMarshaller.CONC_SKIP_LIST_SET:
+ return new PortableLazySet(this, size);
+ }
+
+ throw new PortableException("Unknown collection type: " + colType);
+ }
+
+ case GridPortableMarshaller.MAP:
+ return PortableLazyMap.parseMap(this);
+
+ case GridPortableMarshaller.ENUM:
+ return new PortableBuilderEnum(this);
+
+ case GridPortableMarshaller.ENUM_ARR:
+ return new PortableEnumArrayLazyValue(this);
+
+ case GridPortableMarshaller.MAP_ENTRY:
+ return new PortableLazyMapEntry(this);
+
+ case GridPortableMarshaller.PORTABLE_OBJ: {
+ int size = readInt();
+
+ pos += size;
+
+ int start = readInt();
+
+ PortableObjectImpl portableObj = new PortableObjectImpl(ctx, arr,
+ pos - 4 - size + start);
+
+ return new PortablePlainPortableObject(portableObj);
+ }
+
+
+ default:
+ throw new PortableException("Invalid flag value: " + type);
+ }
+
+ PortablePlainLazyValue res = new PortablePlainLazyValue(this, valPos, 1 + plainLazyValLen);
+
+ pos += plainLazyValLen;
+
+ return res;
+ }
+
+ /**
+ * @return Array.
+ */
+ public byte[] array() {
+ return arr;
+ }
+
+ /**
+ * @return Position of reader.
+ */
+ public int position() {
+ return pos;
+ }
+
+ /**
+ * @param pos New pos.
+ */
+ public void position(int pos) {
+ this.pos = pos;
+ }
+
+ /**
+ * @param n Number of bytes to skip.
+ */
+ public void skip(int n) {
+ pos += n;
+ }
+
+ /**
+ * @return Reader.
+ */
+ PortableReaderExImpl reader() {
+ return reader;
+ }
+
+ /**
+ *
+ */
+ private class LazyCollection implements PortableLazyValue {
+ /** */
+ private final int valOff;
+
+ /** */
+ private Object col;
+
+ /**
+ * @param valOff Value.
+ */
+ protected LazyCollection(int valOff) {
+ this.valOff = valOff;
+ }
+
+ /**
+ * @return Object.
+ */
+ private Object wrappedCollection() {
+ if (col == null) {
+ position(valOff);
+
+ col = parseValue();
+ }
+
+ return col;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeTo(PortableWriterExImpl writer, PortableBuilderSerializer ctx) {
+ ctx.writeValue(writer, wrappedCollection());
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object value() {
+ return PortableUtils.unwrapLazy(wrappedCollection());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/878dcd92/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableBuilderSerializationAware.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableBuilderSerializationAware.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableBuilderSerializationAware.java
new file mode 100644
index 0000000..dadbcf2
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableBuilderSerializationAware.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+/**
+ *
+ */
+interface PortableBuilderSerializationAware {
+ /**
+ * @param writer Writer.
+ * @param ctx Context.
+ */
+ public void writeTo(PortableWriterExImpl writer, PortableBuilderSerializer ctx);
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/878dcd92/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableBuilderSerializer.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableBuilderSerializer.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableBuilderSerializer.java
new file mode 100644
index 0000000..01edc5e
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableBuilderSerializer.java
@@ -0,0 +1,210 @@
+/*
+ * 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.internal.util.*;
+import org.apache.ignite.portable.*;
+
+import java.util.*;
+
+/**
+ *
+ */
+class PortableBuilderSerializer {
+ /** */
+ private final Map<PortableBuilderImpl, Integer> objToPos = new IdentityHashMap<>();
+
+ /** */
+ private Map<PortableObject, PortableBuilderImpl> portableObjToWrapper;
+
+ /**
+ * @param obj Mutable object.
+ * @param posInResArr Object position in the array.
+ */
+ public void registerObjectWriting(PortableBuilderImpl obj, int posInResArr) {
+ objToPos.put(obj, posInResArr);
+ }
+
+ /**
+ * @param writer Writer.
+ * @param val Value.
+ */
+ public void writeValue(PortableWriterExImpl writer, Object val) {
+ if (val == null) {
+ writer.writeByte(GridPortableMarshaller.NULL);
+
+ return;
+ }
+
+ if (val instanceof PortableBuilderSerializationAware) {
+ ((PortableBuilderSerializationAware)val).writeTo(writer, this);
+
+ return;
+ }
+
+ if (val instanceof PortableObjectEx) {
+ if (portableObjToWrapper == null)
+ portableObjToWrapper = new IdentityHashMap<>();
+
+ PortableBuilderImpl wrapper = portableObjToWrapper.get(val);
+
+ if (wrapper == null) {
+ wrapper = PortableBuilderImpl.wrap((PortableObject)val);
+
+ portableObjToWrapper.put((PortableObject)val, wrapper);
+ }
+
+ val = wrapper;
+ }
+
+ if (val instanceof PortableBuilderImpl) {
+ PortableBuilderImpl obj = (PortableBuilderImpl)val;
+
+ Integer posInResArr = objToPos.get(obj);
+
+ if (posInResArr == null) {
+ objToPos.put(obj, writer.outputStream().position());
+
+ obj.serializeTo(writer.newWriter(obj.typeId()), this);
+ }
+ else {
+ int handle = writer.outputStream().position() - posInResArr;
+
+ writer.writeByte(GridPortableMarshaller.HANDLE);
+ writer.writeInt(handle);
+ }
+
+ return;
+ }
+
+ if (val.getClass().isEnum()) {
+ writer.writeByte(GridPortableMarshaller.ENUM);
+ writer.writeInt(writer.context().typeId(val.getClass().getName()));
+ writer.writeInt(((Enum)val).ordinal());
+
+ return;
+ }
+
+ if (val instanceof Collection) {
+ Collection<?> c = (Collection<?>)val;
+
+ writer.writeByte(GridPortableMarshaller.COL);
+ writer.writeInt(c.size());
+
+ byte colType;
+
+ if (c instanceof GridConcurrentSkipListSet)
+ colType = GridPortableMarshaller.CONC_SKIP_LIST_SET;
+ else
+ colType = writer.context().collectionType(c.getClass());
+
+
+ writer.writeByte(colType);
+
+ for (Object obj : c)
+ writeValue(writer, obj);
+
+ return;
+ }
+
+ if (val instanceof Map) {
+ Map<?, ?> map = (Map<?, ?>)val;
+
+ writer.writeByte(GridPortableMarshaller.MAP);
+ writer.writeInt(map.size());
+
+ writer.writeByte(writer.context().mapType(map.getClass()));
+
+ for (Map.Entry<?, ?> entry : map.entrySet()) {
+ writeValue(writer, entry.getKey());
+ writeValue(writer, entry.getValue());
+ }
+
+ return;
+ }
+
+ Byte flag = PortableUtils.PLAIN_CLASS_TO_FLAG.get(val.getClass());
+
+ if (flag != null) {
+ PortableUtils.writePlainObject(writer, val);
+
+ return;
+ }
+
+ if (val instanceof Object[]) {
+ int compTypeId = writer.context().typeId(((Object[])val).getClass().getComponentType().getName());
+
+ if (val instanceof PortableBuilderEnum[]) {
+ writeArray(writer, GridPortableMarshaller.ENUM_ARR, (Object[])val, compTypeId);
+
+ return;
+ }
+
+ if (((Object[])val).getClass().getComponentType().isEnum()) {
+ Enum[] enumArr = (Enum[])val;
+
+ writer.writeByte(GridPortableMarshaller.ENUM_ARR);
+ writer.writeInt(compTypeId);
+ writer.writeInt(enumArr.length);
+
+ for (Enum anEnum : enumArr)
+ writeValue(writer, anEnum);
+
+ return;
+ }
+
+ writeArray(writer, GridPortableMarshaller.OBJ_ARR, (Object[])val, compTypeId);
+
+ return;
+ }
+
+ writer.doWriteObject(val, false);
+ }
+
+ /**
+ * @param writer Writer.
+ * @param elementType Element type.
+ * @param arr The array.
+ * @param compTypeId Component type ID.
+ */
+ public void writeArray(PortableWriterExImpl writer, byte elementType, Object[] arr, int compTypeId) {
+ writer.writeByte(elementType);
+ writer.writeInt(compTypeId);
+ writer.writeInt(arr.length);
+
+ for (Object obj : arr)
+ writeValue(writer, obj);
+ }
+
+ /**
+ * @param writer Writer.
+ * @param elementType Element type.
+ * @param arr The array.
+ * @param clsName Component class name.
+ */
+ public void writeArray(PortableWriterExImpl writer, byte elementType, Object[] arr, String clsName) {
+ writer.writeByte(elementType);
+ writer.writeInt(GridPortableMarshaller.UNREGISTERED_TYPE_ID);
+ writer.writeString(clsName);
+ writer.writeInt(arr.length);
+
+ for (Object obj : arr)
+ writeValue(writer, obj);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/878dcd92/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java
----------------------------------------------------------------------
diff --git 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
new file mode 100644
index 0000000..fb2bdc2
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java
@@ -0,0 +1,1344 @@
+/*
+ * 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.*;
+import org.apache.ignite.internal.processors.cache.*;
+import org.apache.ignite.internal.util.typedef.internal.*;
+import org.apache.ignite.marshaller.*;
+import org.apache.ignite.portable.*;
+
+import org.jetbrains.annotations.*;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.Date;
+
+import static java.lang.reflect.Modifier.*;
+
+/**
+ * Portable class descriptor.
+ */
+class PortableClassDescriptor {
+ /** */
+ private final PortableContext ctx;
+
+ /** */
+ private final Class<?> cls;
+
+ /** */
+ private final PortableSerializer serializer;
+
+ /** */
+ private final Mode mode;
+
+ /** */
+ private final boolean userType;
+
+ /** */
+ private final int typeId;
+
+ /** */
+ private final String typeName;
+
+ /** */
+ private final Constructor<?> ctor;
+
+ /** */
+ private final Collection<FieldInfo> fields;
+
+ /** */
+ private final Method writeReplaceMtd;
+
+ /** */
+ private final Method readResolveMtd;
+
+ /** */
+ private final boolean useTs;
+
+ /** */
+ private final Map<String, String> fieldsMeta;
+
+ /** */
+ private final boolean keepDeserialized;
+
+ /** */
+ private final boolean registered;
+
+ /** */
+ private final boolean excluded;
+
+ /**
+ * @param ctx Context.
+ * @param cls Class.
+ * @param userType User type flag.
+ * @param typeId Type ID.
+ * @param typeName Type name.
+ * @param idMapper ID mapper.
+ * @param serializer Serializer.
+ * @param useTs Use timestamp flag.
+ * @param metaDataEnabled Metadata enabled flag.
+ * @param keepDeserialized Keep deserialized flag.
+ * @throws PortableException In case of error.
+ */
+ PortableClassDescriptor(
+ PortableContext ctx,
+ Class<?> cls,
+ boolean userType,
+ int typeId,
+ String typeName,
+ @Nullable PortableIdMapper idMapper,
+ @Nullable PortableSerializer serializer,
+ boolean useTs,
+ boolean metaDataEnabled,
+ boolean keepDeserialized
+ ) throws PortableException {
+ this(ctx, cls, userType, typeId, typeName, idMapper, serializer, useTs, metaDataEnabled, keepDeserialized,
+ true);
+ }
+
+ /**
+ * @param ctx Context.
+ * @param cls Class.
+ * @param userType User type flag.
+ * @param typeId Type ID.
+ * @param typeName Type name.
+ * @param idMapper ID mapper.
+ * @param serializer Serializer.
+ * @param useTs Use timestamp flag.
+ * @param metaDataEnabled Metadata enabled flag.
+ * @param keepDeserialized Keep deserialized flag.
+ * @param registered Whether typeId has been successfully registered by MarshallerContext or not.
+ * @throws PortableException In case of error.
+ */
+ PortableClassDescriptor(
+ PortableContext ctx,
+ Class<?> cls,
+ boolean userType,
+ int typeId,
+ String typeName,
+ @Nullable PortableIdMapper idMapper,
+ @Nullable PortableSerializer serializer,
+ boolean useTs,
+ boolean metaDataEnabled,
+ boolean keepDeserialized,
+ boolean registered
+ ) throws PortableException {
+ assert ctx != null;
+ assert cls != null;
+
+ this.ctx = ctx;
+ this.cls = cls;
+ this.userType = userType;
+ this.typeId = typeId;
+ this.typeName = typeName;
+ this.serializer = serializer;
+ this.useTs = useTs;
+ this.keepDeserialized = keepDeserialized;
+ this.registered = registered;
+
+ excluded = MarshallerExclusions.isExcluded(cls);
+
+ if (excluded)
+ mode = Mode.EXCLUSION;
+ else
+ mode = serializer != null ? Mode.PORTABLE : mode(cls);
+
+ switch (mode) {
+ case BYTE:
+ case SHORT:
+ case INT:
+ case LONG:
+ case FLOAT:
+ case DOUBLE:
+ case CHAR:
+ case BOOLEAN:
+ case DECIMAL:
+ case STRING:
+ case UUID:
+ case DATE:
+ case BYTE_ARR:
+ case SHORT_ARR:
+ case INT_ARR:
+ case LONG_ARR:
+ case FLOAT_ARR:
+ case DOUBLE_ARR:
+ case CHAR_ARR:
+ case BOOLEAN_ARR:
+ case DECIMAL_ARR:
+ case STRING_ARR:
+ case UUID_ARR:
+ case DATE_ARR:
+ case OBJ_ARR:
+ case COL:
+ case MAP:
+ case MAP_ENTRY:
+ case PORTABLE_OBJ:
+ case ENUM:
+ case ENUM_ARR:
+ case CLASS:
+ case EXCLUSION:
+ ctor = null;
+ fields = null;
+ fieldsMeta = null;
+
+ break;
+
+ case PORTABLE:
+ case EXTERNALIZABLE:
+ ctor = constructor(cls);
+ fields = null;
+ fieldsMeta = null;
+
+ break;
+
+ case OBJECT:
+ assert idMapper != null;
+
+ ctor = constructor(cls);
+ fields = new ArrayList<>();
+ fieldsMeta = metaDataEnabled ? new HashMap<String, String>() : null;
+
+ Collection<String> names = new HashSet<>();
+ Collection<Integer> ids = new HashSet<>();
+
+ for (Class<?> c = cls; c != null && !c.equals(Object.class); c = c.getSuperclass()) {
+ for (Field f : c.getDeclaredFields()) {
+ int mod = f.getModifiers();
+
+ if (!isStatic(mod) && !isTransient(mod)) {
+ f.setAccessible(true);
+
+ String name = f.getName();
+
+ if (!names.add(name))
+ throw new PortableException("Duplicate field name: " + name);
+
+ int fieldId = idMapper.fieldId(typeId, name);
+
+ if (!ids.add(fieldId))
+ throw new PortableException("Duplicate field ID: " + name);
+
+ FieldInfo fieldInfo = new FieldInfo(f, fieldId);
+
+ fields.add(fieldInfo);
+
+ if (metaDataEnabled)
+ fieldsMeta.put(name, fieldInfo.fieldMode().typeName());
+ }
+ }
+ }
+
+ break;
+
+ default:
+ // Should never happen.
+ throw new PortableException("Invalid mode: " + mode);
+ }
+
+ if (mode == Mode.PORTABLE || mode == Mode.EXTERNALIZABLE || mode == Mode.OBJECT) {
+ readResolveMtd = U.findNonPublicMethod(cls, "readResolve");
+ writeReplaceMtd = U.findNonPublicMethod(cls, "writeReplace");
+ }
+ else {
+ readResolveMtd = null;
+ writeReplaceMtd = null;
+ }
+ }
+
+ /**
+ * @return Described class.
+ */
+ Class<?> describedClass() {
+ return cls;
+ }
+
+ /**
+ * @return Type ID.
+ */
+ int typeId() {
+ return typeId;
+ }
+
+ /**
+ * @return Fields meta data.
+ */
+ Map<String, String> fieldsMeta() {
+ return fieldsMeta;
+ }
+
+ /**
+ * @return Use timestamp flag.
+ */
+ boolean isUseTimestamp() {
+ return useTs;
+ }
+
+ /**
+ * @return Keep deserialized flag.
+ */
+ boolean keepDeserialized() {
+ return keepDeserialized;
+ }
+
+ /**
+ * @return Whether typeId has been successfully registered by MarshallerContext or not.
+ */
+ public boolean isRegistered() {
+ return registered;
+ }
+
+ /**
+ * Checks whether the class values are explicitly excluded from marshalling.
+ *
+ * @return {@code true} if excluded, {@code false} otherwise.
+ */
+ public boolean excluded() {
+ return excluded;
+ }
+
+ /**
+ * @return portableWriteReplace() method
+ */
+ @Nullable Method getWriteReplaceMethod() {
+ return writeReplaceMtd;
+ }
+
+ /**
+ * @return portableReadResolve() method
+ */
+ @Nullable Method getReadResolveMethod() {
+ return readResolveMtd;
+ }
+
+ /**
+ * @param obj Object.
+ * @param writer Writer.
+ * @throws PortableException In case of error.
+ */
+ void write(Object obj, PortableWriterExImpl writer) throws PortableException {
+ assert obj != null;
+ assert writer != null;
+
+ switch (mode) {
+ case BYTE:
+ writer.doWriteByte(GridPortableMarshaller.BYTE);
+ writer.doWriteByte((byte)obj);
+
+ break;
+
+ case SHORT:
+ writer.doWriteByte(GridPortableMarshaller.SHORT);
+ writer.doWriteShort((short)obj);
+
+ break;
+
+ case INT:
+ writer.doWriteByte(GridPortableMarshaller.INT);
+ writer.doWriteInt((int)obj);
+
+ break;
+
+ case LONG:
+ writer.doWriteByte(GridPortableMarshaller.LONG);
+ writer.doWriteLong((long)obj);
+
+ break;
+
+ case FLOAT:
+ writer.doWriteByte(GridPortableMarshaller.FLOAT);
+ writer.doWriteFloat((float)obj);
+
+ break;
+
+ case DOUBLE:
+ writer.doWriteByte(GridPortableMarshaller.DOUBLE);
+ writer.doWriteDouble((double)obj);
+
+ break;
+
+ case CHAR:
+ writer.doWriteByte(GridPortableMarshaller.CHAR);
+ writer.doWriteChar((char)obj);
+
+ break;
+
+ case BOOLEAN:
+ writer.doWriteByte(GridPortableMarshaller.BOOLEAN);
+ writer.doWriteBoolean((boolean)obj);
+
+ break;
+
+ case DECIMAL:
+ writer.doWriteDecimal((BigDecimal) obj);
+
+ break;
+
+ case STRING:
+ writer.doWriteString((String)obj);
+
+ break;
+
+ case UUID:
+ writer.doWriteUuid((UUID)obj);
+
+ break;
+
+ case DATE:
+ if (obj instanceof Timestamp)
+ writer.doWriteTimestamp((Timestamp)obj);
+ else
+ writer.doWriteDate((Date)obj);
+
+ break;
+
+ case BYTE_ARR:
+ writer.doWriteByteArray((byte[])obj);
+
+ break;
+
+ case SHORT_ARR:
+ writer.doWriteShortArray((short[])obj);
+
+ break;
+
+ case INT_ARR:
+ writer.doWriteIntArray((int[])obj);
+
+ break;
+
+ case LONG_ARR:
+ writer.doWriteLongArray((long[])obj);
+
+ break;
+
+ case FLOAT_ARR:
+ writer.doWriteFloatArray((float[])obj);
+
+ break;
+
+ case DOUBLE_ARR:
+ writer.doWriteDoubleArray((double[])obj);
+
+ break;
+
+ case CHAR_ARR:
+ writer.doWriteCharArray((char[])obj);
+
+ break;
+
+ case BOOLEAN_ARR:
+ writer.doWriteBooleanArray((boolean[])obj);
+
+ break;
+
+ case DECIMAL_ARR:
+ writer.doWriteDecimalArray((BigDecimal[])obj);
+
+ break;
+
+ case STRING_ARR:
+ writer.doWriteStringArray((String[])obj);
+
+ break;
+
+ case UUID_ARR:
+ writer.doWriteUuidArray((UUID[])obj);
+
+ break;
+
+ case DATE_ARR:
+ writer.doWriteDateArray((Date[])obj);
+
+ break;
+
+ case OBJ_ARR:
+ writer.doWriteObjectArray((Object[])obj);
+
+ break;
+
+ case COL:
+ writer.doWriteCollection((Collection<?>)obj);
+
+ break;
+
+ case MAP:
+ writer.doWriteMap((Map<?, ?>)obj);
+
+ break;
+
+ case MAP_ENTRY:
+ writer.doWriteMapEntry((Map.Entry<?, ?>)obj);
+
+ break;
+
+ case ENUM:
+ writer.doWriteEnum((Enum<?>)obj);
+
+ break;
+
+ case ENUM_ARR:
+ writer.doWriteEnumArray((Object[])obj);
+
+ break;
+
+ case CLASS:
+ writer.doWriteClass((Class)obj);
+
+ break;
+
+ case PORTABLE_OBJ:
+ writer.doWritePortableObject((PortableObjectImpl)obj);
+
+ break;
+
+ case PORTABLE:
+ if (writeHeader(obj, writer)) {
+ if (serializer != null)
+ serializer.writePortable(obj, writer);
+ else
+ ((PortableMarshalAware)obj).writePortable(writer);
+
+ writer.writeRawOffsetIfNeeded();
+ writer.writeLength();
+
+ if (obj.getClass() != PortableMetaDataImpl.class
+ && ctx.isMetaDataChanged(typeId, writer.metaDataHashSum())) {
+ PortableMetaDataCollector metaCollector = new PortableMetaDataCollector(typeName);
+
+ if (serializer != null)
+ serializer.writePortable(obj, metaCollector);
+ else
+ ((PortableMarshalAware)obj).writePortable(metaCollector);
+
+ ctx.updateMetaData(typeId, typeName, metaCollector.meta());
+ }
+ }
+
+ break;
+
+ case EXTERNALIZABLE:
+ if (writeHeader(obj, writer)) {
+ try {
+ ((Externalizable)obj).writeExternal(writer);
+ }
+ catch (IOException e) {
+ throw new PortableException("Failed to write Externalizable object: " + obj, e);
+ }
+
+ writer.writeLength();
+ }
+
+ break;
+
+ case OBJECT:
+ if (writeHeader(obj, writer)) {
+ for (FieldInfo info : fields)
+ info.write(obj, writer);
+
+ writer.writeRawOffsetIfNeeded();
+ writer.writeLength();
+ }
+
+ break;
+
+ default:
+ assert false : "Invalid mode: " + mode;
+ }
+ }
+
+ /**
+ * @param reader Reader.
+ * @return Object.
+ * @throws PortableException If failed.
+ */
+ Object read(PortableReaderExImpl reader) throws PortableException {
+ assert reader != null;
+
+ Object res;
+
+ switch (mode) {
+ case PORTABLE:
+ res = newInstance();
+
+ reader.setHandler(res);
+
+ if (serializer != null)
+ serializer.readPortable(res, reader);
+ else
+ ((PortableMarshalAware)res).readPortable(reader);
+
+ break;
+
+ case EXTERNALIZABLE:
+ res = newInstance();
+
+ reader.setHandler(res);
+
+ try {
+ ((Externalizable)res).readExternal(reader);
+ }
+ catch (IOException | ClassNotFoundException e) {
+ throw new PortableException("Failed to read Externalizable object: " +
+ res.getClass().getName(), e);
+ }
+
+ break;
+
+ case OBJECT:
+ res = newInstance();
+
+ reader.setHandler(res);
+
+ for (FieldInfo info : fields)
+ info.read(res, reader);
+
+ break;
+
+ default:
+ assert false : "Invalid mode: " + mode;
+
+ return null;
+ }
+
+ if (readResolveMtd != null) {
+ try {
+ res = readResolveMtd.invoke(res);
+
+ reader.setHandler(res);
+ }
+ catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ catch (InvocationTargetException e) {
+ if (e.getTargetException() instanceof PortableException)
+ throw (PortableException)e.getTargetException();
+
+ throw new PortableException("Failed to execute readResolve() method on " + res, e);
+ }
+ }
+
+ return res;
+ }
+
+ /**
+ * @param obj Object.
+ * @param writer Writer.
+ * @return Whether further write is needed.
+ */
+ private boolean writeHeader(Object obj, PortableWriterExImpl writer) {
+ int handle = writer.handle(obj);
+
+ if (handle >= 0) {
+ writer.doWriteByte(GridPortableMarshaller.HANDLE);
+ writer.doWriteInt(handle);
+
+ return false;
+ }
+ else {
+ int pos = writer.position();
+
+ writer.doWriteByte(GridPortableMarshaller.OBJ);
+ writer.doWriteBoolean(userType);
+ writer.doWriteInt(registered ? typeId : GridPortableMarshaller.UNREGISTERED_TYPE_ID);
+ writer.doWriteInt(obj instanceof CacheObjectImpl ? 0 : obj.hashCode());
+
+ // For length and raw offset.
+ int reserved = writer.reserve(8);
+
+ // Class name in case if typeId registration is failed.
+ if (!registered)
+ writer.doWriteString(cls.getName());
+
+ int current = writer.position();
+ int len = current - pos;
+
+ // Default raw offset (equal to header length).
+ writer.position(reserved + 4);
+ writer.doWriteInt(len);
+ writer.position(current);
+
+ return true;
+ }
+ }
+
+ /**
+ * @return Instance.
+ * @throws PortableException In case of error.
+ */
+ private Object newInstance() throws PortableException {
+ assert ctor != null;
+
+ try {
+ return ctor.newInstance();
+ }
+ catch (InstantiationException | InvocationTargetException | IllegalAccessException e) {
+ throw new PortableException("Failed to instantiate instance: " + cls, e);
+ }
+ }
+
+ /**
+ * @param cls Class.
+ * @return Constructor.
+ * @throws PortableException If constructor doesn't exist.
+ */
+ @Nullable private static Constructor<?> constructor(Class<?> cls) throws PortableException {
+ assert cls != null;
+
+ try {
+ Constructor<?> ctor = U.forceEmptyConstructor(cls);
+
+ ctor.setAccessible(true);
+
+ return ctor;
+ }
+ catch (IgniteCheckedException e) {
+ throw new PortableException("Failed to get constructor for class: " + cls.getName(), e);
+ }
+ }
+
+ /**
+ * @param cls Class.
+ * @return Mode.
+ */
+ @SuppressWarnings("IfMayBeConditional")
+ private static Mode mode(Class<?> cls) {
+ assert cls != null;
+
+ if (cls == byte.class || cls == Byte.class)
+ return Mode.BYTE;
+ else if (cls == short.class || cls == Short.class)
+ return Mode.SHORT;
+ else if (cls == int.class || cls == Integer.class)
+ return Mode.INT;
+ else if (cls == long.class || cls == Long.class)
+ return Mode.LONG;
+ else if (cls == float.class || cls == Float.class)
+ return Mode.FLOAT;
+ else if (cls == double.class || cls == Double.class)
+ return Mode.DOUBLE;
+ else if (cls == char.class || cls == Character.class)
+ return Mode.CHAR;
+ else if (cls == boolean.class || cls == Boolean.class)
+ return Mode.BOOLEAN;
+ else if (cls == BigDecimal.class)
+ return Mode.DECIMAL;
+ else if (cls == String.class)
+ return Mode.STRING;
+ else if (cls == UUID.class)
+ return Mode.UUID;
+ else if (cls == Timestamp.class || cls == Date.class)
+ return Mode.DATE;
+ else if (cls == byte[].class)
+ return Mode.BYTE_ARR;
+ else if (cls == short[].class)
+ return Mode.SHORT_ARR;
+ else if (cls == int[].class)
+ return Mode.INT_ARR;
+ else if (cls == long[].class)
+ return Mode.LONG_ARR;
+ else if (cls == float[].class)
+ return Mode.FLOAT_ARR;
+ else if (cls == double[].class)
+ return Mode.DOUBLE_ARR;
+ else if (cls == char[].class)
+ return Mode.CHAR_ARR;
+ else if (cls == boolean[].class)
+ return Mode.BOOLEAN_ARR;
+ else if (cls == BigDecimal[].class)
+ return Mode.DECIMAL_ARR;
+ else if (cls == String[].class)
+ return Mode.STRING_ARR;
+ else if (cls == UUID[].class)
+ return Mode.UUID_ARR;
+ else if (cls == Date[].class)
+ return Mode.DATE_ARR;
+ else if (cls.isArray())
+ return cls.getComponentType().isEnum() ? Mode.ENUM_ARR : Mode.OBJ_ARR;
+ else if (cls == PortableObjectImpl.class)
+ return Mode.PORTABLE_OBJ;
+ else if (PortableMarshalAware.class.isAssignableFrom(cls))
+ return Mode.PORTABLE;
+ else if (Externalizable.class.isAssignableFrom(cls))
+ return Mode.EXTERNALIZABLE;
+ else if (Map.Entry.class.isAssignableFrom(cls))
+ return Mode.MAP_ENTRY;
+ else if (Collection.class.isAssignableFrom(cls))
+ return Mode.COL;
+ else if (Map.class.isAssignableFrom(cls))
+ return Mode.MAP;
+ else if (cls == PortableObjectImpl.class)
+ return Mode.PORTABLE_OBJ;
+ else if (cls.isEnum())
+ return Mode.ENUM;
+ else if (cls == Class.class)
+ return Mode.CLASS;
+ else
+ return Mode.OBJECT;
+ }
+
+ /** */
+ private static class FieldInfo {
+ /** */
+ private final Field field;
+
+ /** */
+ private final int id;
+
+ /** */
+ private final Mode mode;
+
+ /**
+ * @param field Field.
+ * @param id Field ID.
+ */
+ private FieldInfo(Field field, int id) {
+ assert field != null;
+
+ this.field = field;
+ this.id = id;
+
+ Class<?> type = field.getType();
+
+ mode = mode(type);
+ }
+
+ /**
+ * @return Field mode.
+ */
+ public Mode fieldMode() {
+ return mode;
+ }
+
+ /**
+ * @param obj Object.
+ * @param writer Writer.
+ * @throws PortableException In case of error.
+ */
+ public void write(Object obj, PortableWriterExImpl writer) throws PortableException {
+ assert obj != null;
+ assert writer != null;
+
+ writer.doWriteInt(id);
+
+ Object val;
+
+ try {
+ val = field.get(obj);
+ }
+ catch (IllegalAccessException e) {
+ throw new PortableException("Failed to get value for field: " + field, e);
+ }
+
+ switch (mode) {
+ case BYTE:
+ writer.writeByteField((Byte)val);
+
+ break;
+
+ case SHORT:
+ writer.writeShortField((Short)val);
+
+ break;
+
+ case INT:
+ writer.writeIntField((Integer)val);
+
+ break;
+
+ case LONG:
+ writer.writeLongField((Long)val);
+
+ break;
+
+ case FLOAT:
+ writer.writeFloatField((Float)val);
+
+ break;
+
+ case DOUBLE:
+ writer.writeDoubleField((Double)val);
+
+ break;
+
+ case CHAR:
+ writer.writeCharField((Character)val);
+
+ break;
+
+ case BOOLEAN:
+ writer.writeBooleanField((Boolean)val);
+
+ break;
+
+ case DECIMAL:
+ writer.writeDecimalField((BigDecimal)val);
+
+ break;
+
+ case STRING:
+ writer.writeStringField((String)val);
+
+ break;
+
+ case UUID:
+ writer.writeUuidField((UUID)val);
+
+ break;
+
+ case DATE:
+ if (val instanceof Timestamp)
+ writer.writeTimestampField((Timestamp)val);
+ else
+ writer.writeDateField((Date)val);
+
+ break;
+
+ case BYTE_ARR:
+ writer.writeByteArrayField((byte[])val);
+
+ break;
+
+ case SHORT_ARR:
+ writer.writeShortArrayField((short[])val);
+
+ break;
+
+ case INT_ARR:
+ writer.writeIntArrayField((int[])val);
+
+ break;
+
+ case LONG_ARR:
+ writer.writeLongArrayField((long[])val);
+
+ break;
+
+ case FLOAT_ARR:
+ writer.writeFloatArrayField((float[])val);
+
+ break;
+
+ case DOUBLE_ARR:
+ writer.writeDoubleArrayField((double[])val);
+
+ break;
+
+ case CHAR_ARR:
+ writer.writeCharArrayField((char[])val);
+
+ break;
+
+ case BOOLEAN_ARR:
+ writer.writeBooleanArrayField((boolean[])val);
+
+ break;
+
+ case DECIMAL_ARR:
+ writer.writeDecimalArrayField((BigDecimal[])val);
+
+ break;
+
+ case STRING_ARR:
+ writer.writeStringArrayField((String[])val);
+
+ break;
+
+ case UUID_ARR:
+ writer.writeUuidArrayField((UUID[])val);
+
+ break;
+
+ case DATE_ARR:
+ writer.writeDateArrayField((Date[])val);
+
+ break;
+
+ case OBJ_ARR:
+ writer.writeObjectArrayField((Object[])val);
+
+ break;
+
+ case COL:
+ writer.writeCollectionField((Collection<?>)val);
+
+ break;
+
+ case MAP:
+ writer.writeMapField((Map<?, ?>)val);
+
+ break;
+
+ case MAP_ENTRY:
+ writer.writeMapEntryField((Map.Entry<?, ?>)val);
+
+ break;
+
+ case PORTABLE_OBJ:
+ writer.writePortableObjectField((PortableObjectImpl)val);
+
+ break;
+
+ case ENUM:
+ writer.writeEnumField((Enum<?>)val);
+
+ break;
+
+ case ENUM_ARR:
+ writer.writeEnumArrayField((Object[])val);
+
+ break;
+
+ case PORTABLE:
+ case EXTERNALIZABLE:
+ case OBJECT:
+ writer.writeObjectField(val);
+
+ break;
+
+ case CLASS:
+ writer.writeClassField((Class)val);
+
+ break;
+
+ default:
+ assert false : "Invalid mode: " + mode;
+ }
+ }
+
+ /**
+ * @param obj Object.
+ * @param reader Reader.
+ * @throws PortableException In case of error.
+ */
+ public void read(Object obj, PortableReaderExImpl reader) throws PortableException {
+ Object val = null;
+
+ switch (mode) {
+ case BYTE:
+ val = reader.readByte(id);
+
+ break;
+
+ case SHORT:
+ val = reader.readShort(id);
+
+ break;
+
+ case INT:
+ val = reader.readInt(id);
+
+ break;
+
+ case LONG:
+ val = reader.readLong(id);
+
+ break;
+
+ case FLOAT:
+ val = reader.readFloat(id);
+
+ break;
+
+ case DOUBLE:
+ val = reader.readDouble(id);
+
+ break;
+
+ case CHAR:
+ val = reader.readChar(id);
+
+ break;
+
+ case BOOLEAN:
+ val = reader.readBoolean(id);
+
+ break;
+
+ case DECIMAL:
+ val = reader.readDecimal(id);
+
+ break;
+
+ case STRING:
+ val = reader.readString(id);
+
+ break;
+
+ case UUID:
+ val = reader.readUuid(id);
+
+ break;
+
+ case DATE:
+ val = field.getType() == Timestamp.class ? reader.readTimestamp(id) : reader.readDate(id);
+
+ break;
+
+ case BYTE_ARR:
+ val = reader.readByteArray(id);
+
+ break;
+
+ case SHORT_ARR:
+ val = reader.readShortArray(id);
+
+ break;
+
+ case INT_ARR:
+ val = reader.readIntArray(id);
+
+ break;
+
+ case LONG_ARR:
+ val = reader.readLongArray(id);
+
+ break;
+
+ case FLOAT_ARR:
+ val = reader.readFloatArray(id);
+
+ break;
+
+ case DOUBLE_ARR:
+ val = reader.readDoubleArray(id);
+
+ break;
+
+ case CHAR_ARR:
+ val = reader.readCharArray(id);
+
+ break;
+
+ case BOOLEAN_ARR:
+ val = reader.readBooleanArray(id);
+
+ break;
+
+ case DECIMAL_ARR:
+ val = reader.readDecimalArray(id);
+
+ break;
+
+ case STRING_ARR:
+ val = reader.readStringArray(id);
+
+ break;
+
+ case UUID_ARR:
+ val = reader.readUuidArray(id);
+
+ break;
+
+ case DATE_ARR:
+ val = reader.readDateArray(id);
+
+ break;
+
+ case OBJ_ARR:
+ val = reader.readObjectArray(id);
+
+ break;
+
+ case COL:
+ val = reader.readCollection(id, null);
+
+ break;
+
+ case MAP:
+ val = reader.readMap(id, null);
+
+ break;
+
+ case MAP_ENTRY:
+ val = reader.readMapEntry(id);
+
+ break;
+
+ case PORTABLE_OBJ:
+ val = reader.readPortableObject(id);
+
+ break;
+
+ case ENUM:
+ val = reader.readEnum(id, field.getType());
+
+ break;
+
+ case ENUM_ARR:
+ val = reader.readEnumArray(id, field.getType().getComponentType());
+
+ break;
+
+ case PORTABLE:
+ case EXTERNALIZABLE:
+ case OBJECT:
+ val = reader.readObject(id);
+
+ break;
+
+ case CLASS:
+ val = reader.readClass(id);
+
+ break;
+
+ default:
+ assert false : "Invalid mode: " + mode;
+ }
+
+ try {
+ if (val != null || !field.getType().isPrimitive())
+ field.set(obj, val);
+ }
+ catch (IllegalAccessException e) {
+ throw new PortableException("Failed to set value for field: " + field, e);
+ }
+ }
+ }
+
+ /** */
+ enum Mode {
+ /** */
+ BYTE("byte"),
+
+ /** */
+ SHORT("short"),
+
+ /** */
+ INT("int"),
+
+ /** */
+ LONG("long"),
+
+ /** */
+ FLOAT("float"),
+
+ /** */
+ DOUBLE("double"),
+
+ /** */
+ CHAR("char"),
+
+ /** */
+ BOOLEAN("boolean"),
+
+ /** */
+ DECIMAL("decimal"),
+
+ /** */
+ STRING("String"),
+
+ /** */
+ UUID("UUID"),
+
+ /** */
+ DATE("Date"),
+
+ /** */
+ BYTE_ARR("byte[]"),
+
+ /** */
+ SHORT_ARR("short[]"),
+
+ /** */
+ INT_ARR("int[]"),
+
+ /** */
+ LONG_ARR("long[]"),
+
+ /** */
+ FLOAT_ARR("float[]"),
+
+ /** */
+ DOUBLE_ARR("double[]"),
+
+ /** */
+ CHAR_ARR("char[]"),
+
+ /** */
+ BOOLEAN_ARR("boolean[]"),
+
+ /** */
+ DECIMAL_ARR("decimal[]"),
+
+ /** */
+ STRING_ARR("String[]"),
+
+ /** */
+ UUID_ARR("UUID[]"),
+
+ /** */
+ DATE_ARR("Date[]"),
+
+ /** */
+ OBJ_ARR("Object[]"),
+
+ /** */
+ COL("Collection"),
+
+ /** */
+ MAP("Map"),
+
+ /** */
+ MAP_ENTRY("Entry"),
+
+ /** */
+ PORTABLE_OBJ("Object"),
+
+ /** */
+ ENUM("Enum"),
+
+ /** */
+ ENUM_ARR("Enum[]"),
+
+ /** */
+ CLASS("Class"),
+
+ /** */
+ PORTABLE("Object"),
+
+ /** */
+ EXTERNALIZABLE("Object"),
+
+ /** */
+ OBJECT("Object"),
+
+ /** */
+ EXCLUSION("Exclusion");
+
+ /** */
+ private final String typeName;
+
+ /**
+ * @param typeName Type name.
+ */
+ Mode(String typeName) {
+ this.typeName = typeName;
+ }
+
+ /**
+ * @return Type name.
+ */
+ String typeName() {
+ return typeName;
+ }
+ }
+}