Ignite-1695 - Fixed reading fields of dynamic type.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/d6bd423a Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/d6bd423a Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/d6bd423a Branch: refs/heads/ignite-1695 Commit: d6bd423aa4438b4f80e88af91e602b7b48150237 Parents: 4bcc431 Author: Alexey Goncharuk <alexey.goncha...@gmail.com> Authored: Tue Dec 1 16:07:12 2015 +0300 Committer: Alexey Goncharuk <alexey.goncha...@gmail.com> Committed: Tue Dec 1 16:07:12 2015 +0300 ---------------------------------------------------------------------- .../internal/portable/BinaryFieldAccessor.java | 83 +++++++++++++++++--- .../internal/portable/BinaryReaderExImpl.java | 11 +++ .../ignite/internal/util/IgniteUtils.java | 8 ++ .../portable/BinaryMarshallerSelfTest.java | 20 +++++ 4 files changed, 111 insertions(+), 11 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/d6bd423a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryFieldAccessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryFieldAccessor.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryFieldAccessor.java index 0eda375..eece245 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryFieldAccessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryFieldAccessor.java @@ -19,6 +19,7 @@ package org.apache.ignite.internal.portable; import org.apache.ignite.binary.BinaryObjectException; import org.apache.ignite.internal.util.GridUnsafe; +import org.apache.ignite.internal.util.typedef.internal.U; import sun.misc.Unsafe; import java.lang.reflect.Field; @@ -74,8 +75,41 @@ public abstract class BinaryFieldAccessor { case P_DOUBLE: return new DoublePrimitiveAccessor(field, id); + case BYTE: + case BOOLEAN: + case SHORT: + case CHAR: + case INT: + case LONG: + case FLOAT: + case DOUBLE: + case DECIMAL: + case STRING: + case UUID: + case DATE: + case TIMESTAMP: + 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 TIMESTAMP_ARR: + case ENUM_ARR: + case OBJECT_ARR: + case PORTABLE_OBJ: + case PORTABLE: + case EXTERNALIZABLE: + return new DefaultFinalClassAccessor(field, id, mode, false); + default: - return new DefaultAccessor(field, id, mode); + return new DefaultFinalClassAccessor(field, id, mode, !U.isFinal(field.getType())); } } @@ -389,10 +423,13 @@ public abstract class BinaryFieldAccessor { /** * Default accessor. */ - private static class DefaultAccessor extends BinaryFieldAccessor { + private static class DefaultFinalClassAccessor extends BinaryFieldAccessor { /** Target field. */ private final Field field; + /** Dynamic accessor flag. */ + private final boolean dynamic; + /** * Constructor. * @@ -400,12 +437,13 @@ public abstract class BinaryFieldAccessor { * @param id Field ID. * @param mode Mode. */ - public DefaultAccessor(Field field, int id, BinaryWriteMode mode) { + DefaultFinalClassAccessor(Field field, int id, BinaryWriteMode mode, boolean dynamic) { super(id, mode); assert field != null; this.field = field; + this.dynamic = dynamic; } /** {@inheritDoc} */ @@ -424,7 +462,7 @@ public abstract class BinaryFieldAccessor { throw new BinaryObjectException("Failed to get value for field: " + field, e); } - switch (mode) { + switch (mode(val)) { case BYTE: writer.writeByteField((Byte) val); @@ -609,6 +647,25 @@ public abstract class BinaryFieldAccessor { /** {@inheritDoc} */ @Override public void read(Object obj, BinaryReaderExImpl reader) throws BinaryObjectException { + Object val = dynamic ? reader.readField(id) : readFixedType(reader); + + try { + if (val != null || !field.getType().isPrimitive()) + field.set(obj, val); + } + catch (IllegalAccessException e) { + throw new BinaryObjectException("Failed to set value for field: " + field, e); + } + } + + /** + * Reads fixed type from the given reader with flags validation. + * + * @param reader Reader to read from. + * @return Read value. + * @throws BinaryObjectException If failed to read value from the stream. + */ + protected Object readFixedType(BinaryReaderExImpl reader) throws BinaryObjectException { Object val = null; switch (mode) { @@ -793,13 +850,17 @@ public abstract class BinaryFieldAccessor { assert false : "Invalid mode: " + mode; } - try { - if (val != null || !field.getType().isPrimitive()) - field.set(obj, val); - } - catch (IllegalAccessException e) { - throw new BinaryObjectException("Failed to set value for field: " + field, e); - } + return val; + } + + /** + * @param val Val to get write mode for. + * @return Write mode. + */ + protected BinaryWriteMode mode(Object val) { + return dynamic ? + val == null ? BinaryWriteMode.OBJECT : PortableUtils.mode(val.getClass()) : + mode; } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/d6bd423a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryReaderExImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryReaderExImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryReaderExImpl.java index b9f851c..ddbf6ba 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryReaderExImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryReaderExImpl.java @@ -1628,6 +1628,17 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Bina } /** + * @return Deserialized object. + * @throws BinaryObjectException If failed. + */ + @Nullable Object readField(int fieldId) throws BinaryObjectException { + if (!findFieldById(fieldId)) + return null; + + return new BinaryReaderExImpl(ctx, in, ldr, hnds).deserialize(); + } + + /** * @param name Field name. * @return Field offset. */ http://git-wip-us.apache.org/repos/asf/ignite/blob/d6bd423a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java index 3dfa9cc..121cd46 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java @@ -7667,6 +7667,14 @@ public abstract class IgniteUtils { } /** + * @param cls Class to check. + * @return {@code True} if class is final. + */ + public static boolean isFinal(Class<?> cls) { + return Modifier.isFinal(cls.getModifiers()); + } + + /** * Gets field value. * * @param cls Class. http://git-wip-us.apache.org/repos/asf/ignite/blob/d6bd423a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryMarshallerSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryMarshallerSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryMarshallerSelfTest.java index 28bc3e5..49be8dd 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryMarshallerSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryMarshallerSelfTest.java @@ -390,6 +390,18 @@ public class BinaryMarshallerSelfTest extends GridCommonAbstractTest { /** * @throws Exception If failed. */ + public void testExternalizableInEnclosing() throws Exception { + SimpleEnclosingObject obj = new SimpleEnclosingObject(); + obj.simpl = new SimpleExternalizable("field"); + + SimpleEnclosingObject other = marshalUnmarshal(obj); + + assertEquals(((SimpleExternalizable)obj.simpl).field, ((SimpleExternalizable)other.simpl).field); + } + + /** + * @throws Exception If failed. + */ public void testMapEntry() throws Exception { Map.Entry<Integer, String> e = new GridMapEntry<>(1, "str1"); @@ -3752,6 +3764,14 @@ public class BinaryMarshallerSelfTest extends GridCommonAbstractTest { /** * */ + public static class SimpleEnclosingObject { + /** */ + private Object simpl; + } + + /** + * + */ public static class SimpleExternalizable implements Externalizable { /** */ private String field;