alex-plekhanov commented on a change in pull request #9490:
URL: https://github.com/apache/ignite/pull/9490#discussion_r750376368
##########
File path:
modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java
##########
@@ -2066,6 +2071,38 @@ public static Object doReadOptimized(BinaryInputStream
in, BinaryContext ctx, @N
return arr;
}
+ /**
+ * @param in Binary input stream.
+ * @param ctx Binary context.
+ * @param ldr Class loader.
+ * @param handles Holder for handles.
+ * @param detach Detach flag.
+ * @param deserialize Deep flag.
+ * @return Value.
+ * @throws BinaryObjectException In case of error.
+ */
+ public static BinaryArray doReadBinaryArray(BinaryInputStream in,
BinaryContext ctx, ClassLoader ldr,
+ BinaryReaderHandlesHolder handles, boolean detach, boolean
deserialize) {
+ int hPos = positionForHandle(in);
+
+ int compTypeId = in.readInt();
+ String compClsName = null;
+
+ if (compTypeId == GridBinaryMarshaller.UNREGISTERED_TYPE_ID)
+ compClsName = doReadClassName(in);
+
+ int len = in.readInt();
+
+ Object[] arr = new Object[len];
+
+ handles.setHandle(arr, hPos);
Review comment:
`BinaryArray` should be stored as a handle, otherwise during the next
read of the same array component type will be lost.
##########
File path:
modules/core/src/main/java/org/apache/ignite/internal/binary/BinarySerializedFieldComparator.java
##########
@@ -288,7 +295,7 @@ else if (val1 instanceof double[])
* @return {@code True} if field is array.
*/
private static boolean isArray(@Nullable Object field) {
- return field != null && field.getClass().isArray();
+ return field != null && (field.getClass().isArray() ||
BinaryArray.class.isAssignableFrom(field.getClass()));
Review comment:
IMO `field instanceof BinaryArray` is more readable (and also a little
bit faster), but it's up to you.
##########
File path:
modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java
##########
@@ -2004,7 +2006,10 @@ public static Object doReadOptimized(BinaryInputStream
in, BinaryContext ctx, @N
return doReadTimeArray(in);
case GridBinaryMarshaller.OBJ_ARR:
- return doReadObjectArray(in, ctx, ldr, handles, detach,
deserialize);
+ if (BinaryArray.useTypedArrays())
Review comment:
`if (BinaryArray.useTypedArrays() && !deserialize)` to avoid
unnecessary wrapping when possible?
##########
File path:
modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformUtils.java
##########
@@ -923,6 +924,8 @@ else if (BinaryUtils.knownMap(o))
return unwrapBinariesIfNeeded((Map<Object, Object>)o);
else if (o instanceof Object[])
return unwrapBinariesInArray((Object[])o);
+ else if (o instanceof BinaryArray)
+ return unwrapBinariesInArray(((BinaryArray)o).deserialize());
Review comment:
Do we really need this condition? BinaryArray.deserialize already unwrap
binaries. And deserialize already called in the next line (since BinaryArray
instanceof BinaryObject)
##########
File path:
modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
##########
@@ -1913,7 +1916,10 @@ private String fieldFlagName(byte flag) {
break;
case OBJ_ARR:
- obj = BinaryUtils.doReadObjectArray(in, ctx, ldr, this, false,
true);
+ if (BinaryArray.useTypedArrays())
+ obj = BinaryUtils.doReadBinaryArray(in, ctx, ldr, this,
false, true).deserialize(ldr);
+ else
Review comment:
Looks redundant (see previous comment).
##########
File path:
modules/core/src/main/java/org/apache/ignite/internal/processors/platform/compute/PlatformCompute.java
##########
@@ -363,7 +364,7 @@ protected Object executeJavaTask(BinaryRawReaderEx reader,
boolean async) throws
IgniteCompute compute0 = computeForTask(nodeIds);
- if (!keepBinary && arg instanceof BinaryObjectImpl)
+ if (!keepBinary && (arg instanceof BinaryObjectImpl || arg instanceof
BinaryArray))
Review comment:
Why only these two types? Binary enum is not possible here?
##########
File path:
modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/service/ClientServiceInvokeRequest.java
##########
@@ -147,6 +148,9 @@ public ClientServiceInvokeRequest(BinaryReaderExImpl
reader) {
IgniteServices services = grp.services();
+ if (BinaryArray.useTypedArrays())
+ GridServiceProxy.KEEP_BINARY.set(true);
Review comment:
Can we introduce some field in GridServiceProxy and pass it as a
constructor parameter? I think there can be problems with thread local - if
service invoke another service. For example, if a local java service was
invoked by thin client and this service invoke another service hosted on
another node - `KEEP_BINARY` flag will be `TRUE` and BinaryObject will be
returned instead regular object to the first service.
Why KEEP BINARY is set only for useTypedArrays? I think it's useful for old
implementation too.
Also, looks like all changes in services and GridTaskWorker are not related
to problems solved by this ticket. All problems with the deserialization of
service invocation results already should be resolved by introducing a binary
array wrapper. Do I miss something?
##########
File path:
modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryArray.java
##########
@@ -0,0 +1,260 @@
+/*
+ * 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.binary;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Objects;
+import org.apache.ignite.IgniteSystemProperties;
+import org.apache.ignite.binary.BinaryObject;
+import org.apache.ignite.binary.BinaryObjectBuilder;
+import org.apache.ignite.binary.BinaryObjectException;
+import org.apache.ignite.binary.BinaryType;
+import org.apache.ignite.internal.GridDirectTransient;
+import org.apache.ignite.internal.processors.cache.CacheObjectUtils;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.internal.util.tostring.GridToStringExclude;
+import org.apache.ignite.internal.util.tostring.GridToStringInclude;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.jetbrains.annotations.Nullable;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_USE_TYPED_ARRAYS;
+
+/**
+ * Binary object representing array.
+ */
+public class BinaryArray implements BinaryObjectEx, Externalizable {
+ /** Default value of {@link
IgniteSystemProperties#IGNITE_USE_TYPED_ARRAYS}. */
+ public static final boolean DFLT_IGNITE_USE_TYPED_ARRAYS = false;
+
+ /** Value of {@link IgniteSystemProperties#IGNITE_USE_TYPED_ARRAYS}. */
+ private static boolean USE_TYPED_ARRAYS =
+ IgniteSystemProperties.getBoolean(IGNITE_USE_TYPED_ARRAYS,
DFLT_IGNITE_USE_TYPED_ARRAYS);
+
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /** Context. */
+ @GridDirectTransient
+ @GridToStringExclude
+ private BinaryContext ctx;
+
+ /** Type ID. */
+ private int compTypeId;
+
+ /** Type class name. */
+ @Nullable private String compClsName;
+
+ /** Values. */
+ @GridToStringInclude(sensitive = true)
+ private Object[] arr;
+
+ /**
+ * {@link Externalizable} support.
+ */
+ public BinaryArray() {
+ // No-op.
+ }
+
+ /**
+ * @param ctx Context.
+ * @param compTypeId Component type id.
+ * @param compClsName Component class name.
+ * @param arr Array.
+ */
+ public BinaryArray(BinaryContext ctx, int compTypeId, @Nullable String
compClsName, Object[] arr) {
+ this.ctx = ctx;
+ this.compTypeId = compTypeId;
+ this.compClsName = compClsName;
+ this.arr = arr;
+ }
+
+ /** {@inheritDoc} */
+ @Override public BinaryType type() throws BinaryObjectException {
+ return BinaryUtils.typeProxy(ctx, this);
+ }
+
+ /** {@inheritDoc} */
+ @Override public @Nullable BinaryType rawType() throws
BinaryObjectException {
+ return BinaryUtils.type(ctx, this);
+ }
+
+ /** {@inheritDoc} */
+ @Override public <T> T deserialize() throws BinaryObjectException {
+ return (T)deserialize(null);
+ }
+
+ /** {@inheritDoc} */
+ @Override public <T> T deserialize(ClassLoader ldr) throws
BinaryObjectException {
+ ClassLoader resolveLdr = ldr == null ?
ctx.configuration().getClassLoader() : ldr;
+
+ if (ldr != null)
+ GridBinaryMarshaller.USE_CACHE.set(Boolean.FALSE);
+
+ try {
+ Class<?> compType = BinaryUtils.resolveClass(ctx, compTypeId,
compClsName, resolveLdr, false);
+
+ Object[] res = Object.class == compType ? arr :
(Object[])Array.newInstance(compType, arr.length);
+
+ boolean keepBinary = BinaryObject.class.isAssignableFrom(compType);
+
+ for (int i = 0; i < arr.length; i++) {
+ Object obj = CacheObjectUtils.unwrapBinaryIfNeeded(null,
arr[i], keepBinary, false, ldr);
+
+ if (!keepBinary && obj != null &&
BinaryObject.class.isAssignableFrom(obj.getClass()))
+ obj = ((BinaryObject)obj).deserialize(ldr);
+
+ res[i] = obj;
+ }
+
+ return (T)res;
+ }
+ finally {
+ GridBinaryMarshaller.USE_CACHE.set(Boolean.TRUE);
+ }
+ }
+
+ /**
+ * @return Underlying array.
+ */
+ public Object[] array() {
+ return arr;
+ }
+
+ /**
+ * @return Component type ID.
+ */
+ public int componentTypeId() {
+ return compTypeId;
+ }
+
+ /**
+ * @return Component class name.
+ */
+ public String componentClassName() {
+ return compClsName;
+ }
+
+ /** {@inheritDoc} */
+ @Override public BinaryObject clone() throws CloneNotSupportedException {
+ return new BinaryArray(ctx, compTypeId, compClsName, arr.clone());
+ }
+
+ /** {@inheritDoc} */
+ @Override public int typeId() {
+ return GridBinaryMarshaller.OBJ_ARR;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeInt(compTypeId);
+ out.writeObject(compClsName);
+ out.writeObject(arr);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
+ ctx = GridBinaryMarshaller.threadLocalContext();
+
+ compTypeId = in.readInt();
+ compClsName = (String)in.readObject();
+ arr = (Object[])in.readObject();
+ }
+
+ /** {@inheritDoc} */
+ @Override public BinaryObjectBuilder toBuilder() throws
BinaryObjectException {
+ throw new UnsupportedOperationException("Builder cannot be created for
array wrapper.");
+ }
+
+ /** {@inheritDoc} */
+ @Override public int enumOrdinal() throws BinaryObjectException {
+ throw new BinaryObjectException("Object is not enum.");
+ }
+
+ /** {@inheritDoc} */
+ @Override public String enumName() throws BinaryObjectException {
+ throw new BinaryObjectException("Object is not enum.");
+ }
+
+ /** {@inheritDoc} */
+ @Override public int size() {
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean isFlagSet(short flag) {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override public <F> F field(String fieldName) throws
BinaryObjectException {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean hasField(String fieldName) {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override public int hashCode() {
+ int result = 31 * Objects.hash(compTypeId);
+
+ result = 31 * result + IgniteUtils.hashCode(arr);
+
+ return result;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean equals(Object o) {
+ if (this == o)
+ return true;
+
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ BinaryArray arr = (BinaryArray)o;
+
+ return compTypeId == arr.compTypeId
+ && Arrays.equals(this.arr, arr.arr);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(BinaryArray.class, this);
+ }
+
+ /** @return {@code True} if typed arrays should be used, {@code false}
otherwise. */
+ public static boolean useTypedArrays() {
+ return USE_TYPED_ARRAYS;
+ }
+
+ /**
+ * Initialize {@link #USE_TYPED_ARRAYS} value with
+ * {@link IgniteSystemProperties#IGNITE_USE_TYPED_ARRAYS} system property
value.
+ *
+ * This method invoked using reflection in tests.
+ */
+ public static void initUseTypedArrays() {
+ USE_TYPED_ARRAYS =
IgniteSystemProperties.getBoolean(IGNITE_USE_TYPED_ARRAYS,
DFLT_IGNITE_USE_TYPED_ARRAYS);
Review comment:
I think the logic based on a static field that can be modified
dynamically in runtime is fragile. Perhaps it could be moved to some non-static
field of Ignite-instance-singleton object (for example `BinaryContext`, but I'm
not sure it's available in all places where `useTypedArrays` is invoked). WDYT?
##########
File path:
modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryArraySelfTest.java
##########
@@ -0,0 +1,348 @@
+/*
+ * 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.binary;
+
+import java.util.Arrays;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.binary.BinaryObject;
+import org.apache.ignite.internal.binary.BinaryMarshallerSelfTest.TestClass1;
+import org.apache.ignite.internal.processors.platform.utils.PlatformUtils;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.junit.Test;
+
+/** */
+public class BinaryArraySelfTest extends AbstractTypedArrayTest {
+ /** */
+ private static Ignite server;
+
+ /** */
+ private static Ignite client;
+
+ /** */
+ private static IgniteCache<Object, Object> srvCache;
+
+ /** */
+ private static IgniteCache<Object, Object> cliCache;
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTestsStarted() throws Exception {
+ super.beforeTestsStarted();
+
+ server = startGrid(0);
+ client = startClientGrid(1);
+
+ srvCache = server.createCache("my-cache");
+ cliCache = client.getOrCreateCache("my-cache");
+ }
+
+ /** */
+ @Test
+ public void testArrayKey() {
+ doTestArrayKey(srvCache);
+ doTestArrayKey(cliCache);
+ }
+
+ /** */
+ @Test
+ public void testArrayValue() {
+ doTestArrayValue(srvCache);
+ doTestArrayValue(cliCache);
+ }
+
+ /** */
+ @Test
+ public void testArrayFieldInKey() {
+ doTestArrayFieldInKey(srvCache);
+ doTestArrayFieldInKey(cliCache);
+ }
+
+ /** */
+ @Test
+ public void testArrayFieldInValue() {
+ doTestArrayFieldInValue(srvCache);
+ doTestArrayFieldInValue(cliCache);
+ }
+
+ /** */
+ @Test
+ public void testBoxedPrimitivesArrays() {
+ doTestBoxedPrimitivesArrays(srvCache);
+ doTestBoxedPrimitivesArrays(cliCache);
+ }
+
+ /** */
+ @Test
+ public void testBinaryModeArray() {
+ doTestBinaryModeArray(srvCache);
+ doTestBinaryModeArray(cliCache);
+ }
+
+ /** */
+ private void doTestArrayKey(IgniteCache<Object, Object> c) {
+ TestClass1[] key1 = {new TestClass1(), new TestClass1()};
+ TestClass1[] key2 = {};
+ TestClass1[] key3 = new TestClass1[] {new TestClass1() {}};
+
+ c.put(key1, 1);
+ c.put(key2, 2);
+ c.put(key3, 3);
+
+ assertEquals(1, c.get(key1));
+ assertEquals(2, c.get(key2));
+ assertEquals(3, c.get(key3));
+
+ assertTrue(c.replace(key1, 1, 2));
+ assertTrue(c.replace(key2, 2, 3));
+ assertTrue(c.replace(key3, 3, 4));
+
+ assertTrue(c.remove(key1));
+ assertTrue(c.remove(key2));
+ assertTrue(c.remove(key3));
+ }
+
+ /** */
+ private void doTestArrayFieldInKey(IgniteCache<Object, Object> c) {
+ TestClass key1 = new TestClass(new TestClass1[] {new TestClass1(), new
TestClass1()});
+ TestClass key2 = new TestClass(new TestClass1[] {});
+ TestClass key3 = new TestClass(new TestClass1[] {new TestClass1() {}});
+
+ c.put(key1, 1);
+ c.put(key2, 2);
+ c.put(key3, 3);
+
+ assertEquals(1, c.get(key1));
+ assertEquals(2, c.get(key2));
+ assertEquals(3, c.get(key3));
+
+ assertTrue(c.replace(key1, 1, 2));
+ assertTrue(c.replace(key2, 2, 3));
+ assertTrue(c.replace(key3, 3, 4));
+
+ assertTrue(c.remove(key1));
+ assertTrue(c.remove(key2));
+ assertTrue(c.remove(key3));
+ }
+
+ /** */
+ private void doTestArrayValue(IgniteCache<Object, Object> c) {
+ c.put(1, new TestClass1[] {new TestClass1(), new TestClass1()});
+ c.put(2, new TestClass1[] {});
+ c.put(3, new TestClass1[] {new TestClass1() {}});
+
+ Object val1 = c.get(1);
+ Object val2 = c.get(2);
+ Object val3 = c.get(3);
+
+ assertEquals(useTypedArrays ? TestClass1[].class : Object[].class,
val1.getClass());
+ assertEquals(useTypedArrays ? TestClass1[].class : Object[].class,
val2.getClass());
+ assertEquals(useTypedArrays ? TestClass1[].class : Object[].class,
val3.getClass());
+
+ if (useTypedArrays) {
+ assertTrue(c.replace(1, val1, val2));
+ assertTrue(c.replace(2, val2, val3));
+ assertTrue(c.replace(3, val3, val1));
+ }
+
+ assertTrue(c.remove(1));
+ assertTrue(c.remove(2));
+ assertTrue(c.remove(3));
+ }
+
+ /** */
+ private void doTestArrayFieldInValue(IgniteCache<Object, Object> c) {
+ c.put(1, new TestClass(new TestClass1[] {new TestClass1(), new
TestClass1()}));
+ c.put(2, new TestClass(new TestClass1[] {}));
+ c.put(3, new TestClass(new TestClass1[] {new TestClass1() {}}));
+
+ TestClass val1 = (TestClass)c.get(1);
+ TestClass val2 = (TestClass)c.get(2);
+ TestClass val3 = (TestClass)c.get(3);
+
+ assertEquals(2, val1.getArr().length);
+ assertEquals(0, val2.getArr().length);
+ assertEquals(1, val3.getArr().length);
+
+ if (useTypedArrays) {
+ assertTrue(c.replace(1, val1, val2));
+ assertTrue(c.replace(2, val2, val3));
+ assertTrue(c.replace(3, val3, val1));
+ }
+
+ assertTrue(c.remove(1));
+ assertTrue(c.remove(2));
+ assertTrue(c.remove(3));
+ }
+
+ /** */
+ private void doTestBinaryModeArray(IgniteCache<Object, Object> c) {
+ c.put(1, new TestClass1[] {new TestClass1(), new TestClass1()});
+ Object obj = c.withKeepBinary().get(1);
+
+ assertEquals(useTypedArrays ? BinaryArray.class : Object[].class,
obj.getClass());
+
+ if (useTypedArrays)
+ assertEquals(TestClass1[].class,
((BinaryObject)obj).deserialize().getClass());
+
+ assertTrue(c.remove(1));
+ }
+
+ /** */
+ private void doTestBoxedPrimitivesArrays(IgniteCache<Object, Object> c) {
+ Object[] data = new Object[] {
+ new Byte[] {1, 2, 3},
+ new Short[] {1, 2, 3},
+ new Integer[] {1, 2, 3},
+ new Long[] {1L, 2L, 3L},
+ new Float[] {1f, 2f, 3f},
+ new Double[] {1d, 2d, 3d},
+ new Character[] {'a', 'b', 'c'},
+ new Boolean[] {true, false},
+ };
+
+ for (Object item : data) {
+ c.put(1, item);
+
+ Object item0 = c.get(1);
+
+ if (useTypedArrays)
+ assertTrue(c.replace(1, item, item));
+
+ assertTrue(c.remove(1));
+
+ if (useTypedArrays)
+ assertEquals(item.getClass(), item0.getClass());
+
+ assertTrue(Arrays.equals((Object[])item, (Object[])item0));
+
+ c.put(item, 1);
+
+ assertEquals(1, c.get(item));
+
+ if (useTypedArrays)
+ assertTrue(c.replace(item, 1, 2));
+
+ assertTrue(c.remove(item));
+ }
+ }
+
+ /** */
+ @Test
+ public void testArrayOfBinariesSerDe() {
+ BinaryObject[] arr = new BinaryObject[] {
+ server.binary().toBinary(new TestClass1()),
+ server.binary().toBinary(new TestClass1())
+ };
+
+ Object obj = server.binary().toBinary(arr);
+
+ Object deser;
+
+ if (useTypedArrays) {
+ assertTrue(obj instanceof BinaryArray);
+
+ deser = ((BinaryArray)obj).deserialize();
+ }
+ else {
+ assertTrue(obj instanceof Object[]);
+
+ deser = PlatformUtils.unwrapBinariesInArray((Object[])obj);
+ }
+
+ assertEquals(Object[].class, deser.getClass());
+
+ Object[] res = ((Object[])deser);
+
+ assertEquals(2, res.length);
+ assertTrue(res[0] instanceof TestClass1);
+ assertTrue(res[1] instanceof TestClass1);
+
Review comment:
redundant NL
##########
File path:
modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryArraySelfTest.java
##########
@@ -0,0 +1,348 @@
+/*
+ * 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.binary;
+
+import java.util.Arrays;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.binary.BinaryObject;
+import org.apache.ignite.internal.binary.BinaryMarshallerSelfTest.TestClass1;
+import org.apache.ignite.internal.processors.platform.utils.PlatformUtils;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.junit.Test;
+
+/** */
+public class BinaryArraySelfTest extends AbstractTypedArrayTest {
+ /** */
+ private static Ignite server;
+
+ /** */
+ private static Ignite client;
+
+ /** */
+ private static IgniteCache<Object, Object> srvCache;
+
+ /** */
+ private static IgniteCache<Object, Object> cliCache;
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTestsStarted() throws Exception {
+ super.beforeTestsStarted();
+
+ server = startGrid(0);
+ client = startClientGrid(1);
+
+ srvCache = server.createCache("my-cache");
+ cliCache = client.getOrCreateCache("my-cache");
+ }
+
+ /** */
+ @Test
+ public void testArrayKey() {
+ doTestArrayKey(srvCache);
+ doTestArrayKey(cliCache);
+ }
+
+ /** */
+ @Test
+ public void testArrayValue() {
+ doTestArrayValue(srvCache);
+ doTestArrayValue(cliCache);
+ }
+
+ /** */
+ @Test
+ public void testArrayFieldInKey() {
+ doTestArrayFieldInKey(srvCache);
+ doTestArrayFieldInKey(cliCache);
+ }
+
+ /** */
+ @Test
+ public void testArrayFieldInValue() {
+ doTestArrayFieldInValue(srvCache);
+ doTestArrayFieldInValue(cliCache);
+ }
+
+ /** */
+ @Test
+ public void testBoxedPrimitivesArrays() {
+ doTestBoxedPrimitivesArrays(srvCache);
+ doTestBoxedPrimitivesArrays(cliCache);
+ }
+
+ /** */
+ @Test
+ public void testBinaryModeArray() {
+ doTestBinaryModeArray(srvCache);
+ doTestBinaryModeArray(cliCache);
+ }
+
+ /** */
+ private void doTestArrayKey(IgniteCache<Object, Object> c) {
+ TestClass1[] key1 = {new TestClass1(), new TestClass1()};
+ TestClass1[] key2 = {};
+ TestClass1[] key3 = new TestClass1[] {new TestClass1() {}};
+
+ c.put(key1, 1);
+ c.put(key2, 2);
+ c.put(key3, 3);
+
+ assertEquals(1, c.get(key1));
+ assertEquals(2, c.get(key2));
+ assertEquals(3, c.get(key3));
+
+ assertTrue(c.replace(key1, 1, 2));
+ assertTrue(c.replace(key2, 2, 3));
+ assertTrue(c.replace(key3, 3, 4));
+
+ assertTrue(c.remove(key1));
+ assertTrue(c.remove(key2));
+ assertTrue(c.remove(key3));
+ }
+
+ /** */
+ private void doTestArrayFieldInKey(IgniteCache<Object, Object> c) {
+ TestClass key1 = new TestClass(new TestClass1[] {new TestClass1(), new
TestClass1()});
+ TestClass key2 = new TestClass(new TestClass1[] {});
+ TestClass key3 = new TestClass(new TestClass1[] {new TestClass1() {}});
+
+ c.put(key1, 1);
+ c.put(key2, 2);
+ c.put(key3, 3);
+
+ assertEquals(1, c.get(key1));
+ assertEquals(2, c.get(key2));
+ assertEquals(3, c.get(key3));
+
+ assertTrue(c.replace(key1, 1, 2));
+ assertTrue(c.replace(key2, 2, 3));
+ assertTrue(c.replace(key3, 3, 4));
+
+ assertTrue(c.remove(key1));
+ assertTrue(c.remove(key2));
+ assertTrue(c.remove(key3));
+ }
+
+ /** */
+ private void doTestArrayValue(IgniteCache<Object, Object> c) {
+ c.put(1, new TestClass1[] {new TestClass1(), new TestClass1()});
+ c.put(2, new TestClass1[] {});
+ c.put(3, new TestClass1[] {new TestClass1() {}});
+
+ Object val1 = c.get(1);
+ Object val2 = c.get(2);
+ Object val3 = c.get(3);
+
+ assertEquals(useTypedArrays ? TestClass1[].class : Object[].class,
val1.getClass());
+ assertEquals(useTypedArrays ? TestClass1[].class : Object[].class,
val2.getClass());
+ assertEquals(useTypedArrays ? TestClass1[].class : Object[].class,
val3.getClass());
+
+ if (useTypedArrays) {
+ assertTrue(c.replace(1, val1, val2));
+ assertTrue(c.replace(2, val2, val3));
+ assertTrue(c.replace(3, val3, val1));
+ }
+
+ assertTrue(c.remove(1));
+ assertTrue(c.remove(2));
+ assertTrue(c.remove(3));
+ }
+
+ /** */
+ private void doTestArrayFieldInValue(IgniteCache<Object, Object> c) {
+ c.put(1, new TestClass(new TestClass1[] {new TestClass1(), new
TestClass1()}));
+ c.put(2, new TestClass(new TestClass1[] {}));
+ c.put(3, new TestClass(new TestClass1[] {new TestClass1() {}}));
+
+ TestClass val1 = (TestClass)c.get(1);
+ TestClass val2 = (TestClass)c.get(2);
+ TestClass val3 = (TestClass)c.get(3);
+
+ assertEquals(2, val1.getArr().length);
+ assertEquals(0, val2.getArr().length);
+ assertEquals(1, val3.getArr().length);
+
+ if (useTypedArrays) {
+ assertTrue(c.replace(1, val1, val2));
+ assertTrue(c.replace(2, val2, val3));
+ assertTrue(c.replace(3, val3, val1));
+ }
+
+ assertTrue(c.remove(1));
+ assertTrue(c.remove(2));
+ assertTrue(c.remove(3));
+ }
+
+ /** */
+ private void doTestBinaryModeArray(IgniteCache<Object, Object> c) {
+ c.put(1, new TestClass1[] {new TestClass1(), new TestClass1()});
+ Object obj = c.withKeepBinary().get(1);
+
+ assertEquals(useTypedArrays ? BinaryArray.class : Object[].class,
obj.getClass());
+
+ if (useTypedArrays)
+ assertEquals(TestClass1[].class,
((BinaryObject)obj).deserialize().getClass());
+
+ assertTrue(c.remove(1));
+ }
+
+ /** */
+ private void doTestBoxedPrimitivesArrays(IgniteCache<Object, Object> c) {
+ Object[] data = new Object[] {
+ new Byte[] {1, 2, 3},
+ new Short[] {1, 2, 3},
+ new Integer[] {1, 2, 3},
+ new Long[] {1L, 2L, 3L},
+ new Float[] {1f, 2f, 3f},
+ new Double[] {1d, 2d, 3d},
+ new Character[] {'a', 'b', 'c'},
+ new Boolean[] {true, false},
+ };
+
+ for (Object item : data) {
+ c.put(1, item);
+
+ Object item0 = c.get(1);
+
+ if (useTypedArrays)
+ assertTrue(c.replace(1, item, item));
+
+ assertTrue(c.remove(1));
+
+ if (useTypedArrays)
+ assertEquals(item.getClass(), item0.getClass());
+
+ assertTrue(Arrays.equals((Object[])item, (Object[])item0));
+
+ c.put(item, 1);
+
+ assertEquals(1, c.get(item));
+
+ if (useTypedArrays)
+ assertTrue(c.replace(item, 1, 2));
+
+ assertTrue(c.remove(item));
+ }
+ }
+
+ /** */
+ @Test
+ public void testArrayOfBinariesSerDe() {
+ BinaryObject[] arr = new BinaryObject[] {
+ server.binary().toBinary(new TestClass1()),
+ server.binary().toBinary(new TestClass1())
+ };
+
+ Object obj = server.binary().toBinary(arr);
+
+ Object deser;
+
+ if (useTypedArrays) {
+ assertTrue(obj instanceof BinaryArray);
+
+ deser = ((BinaryArray)obj).deserialize();
+ }
+ else {
+ assertTrue(obj instanceof Object[]);
+
+ deser = PlatformUtils.unwrapBinariesInArray((Object[])obj);
+ }
+
+ assertEquals(Object[].class, deser.getClass());
Review comment:
Why for `BinaryObject[]` class `Object[]` is returned? Any compatibility
issues?
##########
File path:
modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryArray.java
##########
@@ -0,0 +1,260 @@
+/*
+ * 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.binary;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Objects;
+import org.apache.ignite.IgniteSystemProperties;
+import org.apache.ignite.binary.BinaryObject;
+import org.apache.ignite.binary.BinaryObjectBuilder;
+import org.apache.ignite.binary.BinaryObjectException;
+import org.apache.ignite.binary.BinaryType;
+import org.apache.ignite.internal.GridDirectTransient;
+import org.apache.ignite.internal.processors.cache.CacheObjectUtils;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.internal.util.tostring.GridToStringExclude;
+import org.apache.ignite.internal.util.tostring.GridToStringInclude;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.jetbrains.annotations.Nullable;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_USE_TYPED_ARRAYS;
+
+/**
+ * Binary object representing array.
+ */
+public class BinaryArray implements BinaryObjectEx, Externalizable {
+ /** Default value of {@link
IgniteSystemProperties#IGNITE_USE_TYPED_ARRAYS}. */
+ public static final boolean DFLT_IGNITE_USE_TYPED_ARRAYS = false;
+
+ /** Value of {@link IgniteSystemProperties#IGNITE_USE_TYPED_ARRAYS}. */
+ private static boolean USE_TYPED_ARRAYS =
+ IgniteSystemProperties.getBoolean(IGNITE_USE_TYPED_ARRAYS,
DFLT_IGNITE_USE_TYPED_ARRAYS);
+
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /** Context. */
+ @GridDirectTransient
+ @GridToStringExclude
+ private BinaryContext ctx;
+
+ /** Type ID. */
+ private int compTypeId;
+
+ /** Type class name. */
+ @Nullable private String compClsName;
+
+ /** Values. */
+ @GridToStringInclude(sensitive = true)
+ private Object[] arr;
+
+ /**
+ * {@link Externalizable} support.
+ */
+ public BinaryArray() {
+ // No-op.
+ }
+
+ /**
+ * @param ctx Context.
+ * @param compTypeId Component type id.
+ * @param compClsName Component class name.
+ * @param arr Array.
+ */
+ public BinaryArray(BinaryContext ctx, int compTypeId, @Nullable String
compClsName, Object[] arr) {
+ this.ctx = ctx;
+ this.compTypeId = compTypeId;
+ this.compClsName = compClsName;
+ this.arr = arr;
+ }
+
+ /** {@inheritDoc} */
+ @Override public BinaryType type() throws BinaryObjectException {
+ return BinaryUtils.typeProxy(ctx, this);
+ }
+
+ /** {@inheritDoc} */
+ @Override public @Nullable BinaryType rawType() throws
BinaryObjectException {
+ return BinaryUtils.type(ctx, this);
+ }
+
+ /** {@inheritDoc} */
+ @Override public <T> T deserialize() throws BinaryObjectException {
+ return (T)deserialize(null);
+ }
+
+ /** {@inheritDoc} */
+ @Override public <T> T deserialize(ClassLoader ldr) throws
BinaryObjectException {
+ ClassLoader resolveLdr = ldr == null ?
ctx.configuration().getClassLoader() : ldr;
+
+ if (ldr != null)
+ GridBinaryMarshaller.USE_CACHE.set(Boolean.FALSE);
+
+ try {
+ Class<?> compType = BinaryUtils.resolveClass(ctx, compTypeId,
compClsName, resolveLdr, false);
+
+ Object[] res = Object.class == compType ? arr :
(Object[])Array.newInstance(compType, arr.length);
+
+ boolean keepBinary = BinaryObject.class.isAssignableFrom(compType);
+
+ for (int i = 0; i < arr.length; i++) {
+ Object obj = CacheObjectUtils.unwrapBinaryIfNeeded(null,
arr[i], keepBinary, false, ldr);
+
+ if (!keepBinary && obj != null &&
BinaryObject.class.isAssignableFrom(obj.getClass()))
Review comment:
`obj != null && BinaryObject.class.isAssignableFrom(obj.getClass())` can
be simplified to `obj instanceof BinaryObject`
##########
File path:
modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java
##########
@@ -2554,6 +2591,41 @@ public static void validateEnumValues(String typeName,
@Nullable Map<String, Int
return mergedMap;
}
+ /**
+ * @param obj {@link BinaryArray} or {@code Object[]}.
+ * @return Objects array.
+ */
+ public static Object[] rawArrayFromBinary(Object obj) {
+ if (obj instanceof BinaryArray)
+ // We want raw data(no deserialization).
+ return ((BinaryArray)obj).array();
+ else
+ // This can happen even in BinaryArray.USE_TYPED_ARRAY = true.
+ // In case user pass special array type to arguments, String[],
for example.
+ return (Object[])obj;
+ }
+
+ /** */
+ public static Object[] rawArrayInArgs(Object[] args, boolean keepBinary) {
+ if (args == null)
+ return args;
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i] instanceof BinaryArray) {
+ BinaryArray arr = (BinaryArray)args[i];
+
+ args[i] = keepBinary ? arr.array() : arr.deserialize();
+ }
+ }
+
+ return args;
+ }
+
+ /** */
+ public static boolean isObjectArray(Class<?> cls) {
+ return Object[].class == cls || BinaryArray.class == cls;
Review comment:
`BinaryArray.class.isAssignableFrom(cls)` or
`cls.isInstance(BinaryArray.class)` to consistency with other usages?
##########
File path:
modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProxy.java
##########
@@ -486,7 +536,7 @@ private Object callService(Service srv, Method mtd) throws
Exception {
throw new GridServiceMethodNotFoundException(svcName, mtdName,
argTypes);
try {
- return mtd.invoke(srv, args);
+ return mtd.invoke(srv, BinaryUtils.rawArrayInArgs(args,
false));
Review comment:
We can marshall result to `bytes[]` here and unmarshall on reduce node
with or without deserialization instead of introducing the new class and making
GridTaskWorker coupled with this class. WDYT?
##########
File path:
modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/DmlUtils.java
##########
@@ -111,6 +112,18 @@ public static Object convert(Object val,
GridH2RowDescriptor desc, Class<?> expC
// We have to convert arrays of reference types manually -
// see https://issues.apache.org/jira/browse/IGNITE-4327
// Still, we only can convert from Object[] to something more
precise.
+ if (type == Value.ARRAY && val instanceof BinaryArray) {
+ val = ((BinaryArray)val).deserialize();
Review comment:
Looks suspicious. If we have `BinaryArray` here, then `val` should be
binary, but here we deserialize it and binary objects will coexist with regular
objects in the same context.
##########
File path:
modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
##########
@@ -1364,7 +1364,10 @@ float readFloat(int fieldId) throws
BinaryObjectException {
@Nullable @Override public Object[] readObjectArray() throws
BinaryObjectException {
switch (checkFlag(OBJ_ARR)) {
case NORMAL:
- return BinaryUtils.doReadObjectArray(in, ctx, ldr, this,
false, true);
+ if (BinaryArray.useTypedArrays())
+ return BinaryUtils.doReadBinaryArray(in, ctx, ldr, this,
false, true).deserialize(ldr);
+ else
Review comment:
Looks redundant. When we read array with the `deserialize` flag we have
component type information and can create a corresponding array, so addition
wrapper/unwrapper to/from `BinaryArray` is not required.
##########
File path:
modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryObjectToStringTest.java
##########
@@ -85,6 +84,8 @@ public void
testToStringInaccessibleOptimizedMarshallerClass() throws Exception
assertStringFormMatches(new TestContainer(new
TestExternalizable(newExtInstance1())),
failedStrPattern("ExternalTestClass1"));
+
+ stopAllGrids();
Review comment:
It should be in the `finally` block, or in the `afterTest()` method.
##########
File path:
modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryObjectBuilderDefaultMappersSelfTest.java
##########
@@ -857,10 +856,18 @@ public void testMetaData() throws Exception {
Collection<String> fields = meta.fieldNames();
- assertEquals(2, fields.size());
+ switch (fields.size()) {
Review comment:
It's not trivial to understand why there can be different count of
fields, let's use different class names for different test runs instead (for
example `"org.test.MetaTest" + (useTypedArray ? "1" : "0")`) and revert this
changes to make test more clear.
##########
File path:
modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProxy.java
##########
@@ -198,10 +203,29 @@ else if (U.isToStringMethod(mtd))
else {
ctx.task().setThreadContext(TC_IO_POLICY,
GridIoPolicy.SERVICE_POOL);
+ ServiceProxyCallable svcCallable;
Review comment:
What about services tests with enabled "use binary array" property? I
think it should be added at least to thin client `ServicesTest`. Perhaps for
.NET services tests too.
##########
File path:
modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformUtils.java
##########
@@ -1063,12 +1066,17 @@ public static void initializeJavaObject(Object obj,
String clsName, @Nullable Ma
throw new IgniteException("Java object/factory class field
is not found [" +
"className=" + clsName + ", fieldName=" + fieldName +
']');
+ Object val = prop.getValue();
+
try {
- field.set(obj, prop.getValue());
+ field.set(
+ obj,
+ BinaryUtils.isObjectArray(field.getType()) ?
BinaryUtils.rawArrayFromBinary(val) : val
Review comment:
Looks suspiciously. If we have `BinaryArray` here, then the field value
is not deserialized. Initializing java object field with not deserialized field
value may lead to some hidden problems. Perhaps, props should be read with
deserialization (for example, with `readObject()` method instead of
`readObjectDetached()`).
##########
File path:
modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java
##########
@@ -2554,6 +2591,41 @@ public static void validateEnumValues(String typeName,
@Nullable Map<String, Int
return mergedMap;
}
+ /**
+ * @param obj {@link BinaryArray} or {@code Object[]}.
+ * @return Objects array.
+ */
+ public static Object[] rawArrayFromBinary(Object obj) {
+ if (obj instanceof BinaryArray)
+ // We want raw data(no deserialization).
+ return ((BinaryArray)obj).array();
+ else
+ // This can happen even in BinaryArray.USE_TYPED_ARRAY = true.
+ // In case user pass special array type to arguments, String[],
for example.
+ return (Object[])obj;
+ }
+
+ /** */
+ public static Object[] rawArrayInArgs(Object[] args, boolean keepBinary) {
+ if (args == null)
+ return args;
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i] instanceof BinaryArray) {
+ BinaryArray arr = (BinaryArray)args[i];
+
+ args[i] = keepBinary ? arr.array() : arr.deserialize();
Review comment:
Why only `BinaryArray`'s are deserialized? What about regular binary
objects? With such a behavior binary objects and regular objects will coexist
in the same args array, I think it's error-prone.
##########
File path:
modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java
##########
@@ -153,6 +154,12 @@
/** Binary enum */
public static final byte BINARY_ENUM = 38;
+ /**
+ * {@link BinaryObject} interface type id.
+ * Used to store array component type in case of {@code BinaryObject[]}.
+ */
+ public static final byte BINARY_OBJ_INTERFACE = 39;
Review comment:
As far as I understand this type was introduced only to support
BinaryArray[] in .NET? I see no test was modified in .NET, do we already have a
test for this functionality? Why this type is not supported in java? I mean, if
we `put(0, new BinaryObject[] {})` to cache and then `get(0)` from cache -
result will be `Object[]`
##########
File path:
modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java
##########
@@ -1869,6 +1885,8 @@ public void testMetadataRemote() throws Exception {
assertResponseContainsError(content("nonExistingCacheName",
GridRestCommand.CACHE_METADATA),
"Failed to request meta data. nonExistingCacheName is not found");
+
+ grid(1).destroyCache("partial");
Review comment:
Should be in `finally` block.
##########
File path:
modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryArray.java
##########
@@ -0,0 +1,260 @@
+/*
+ * 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.binary;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Objects;
+import org.apache.ignite.IgniteSystemProperties;
+import org.apache.ignite.binary.BinaryObject;
+import org.apache.ignite.binary.BinaryObjectBuilder;
+import org.apache.ignite.binary.BinaryObjectException;
+import org.apache.ignite.binary.BinaryType;
+import org.apache.ignite.internal.GridDirectTransient;
+import org.apache.ignite.internal.processors.cache.CacheObjectUtils;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.internal.util.tostring.GridToStringExclude;
+import org.apache.ignite.internal.util.tostring.GridToStringInclude;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.jetbrains.annotations.Nullable;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_USE_TYPED_ARRAYS;
+
+/**
+ * Binary object representing array.
+ */
+public class BinaryArray implements BinaryObjectEx, Externalizable {
+ /** Default value of {@link
IgniteSystemProperties#IGNITE_USE_TYPED_ARRAYS}. */
+ public static final boolean DFLT_IGNITE_USE_TYPED_ARRAYS = false;
+
+ /** Value of {@link IgniteSystemProperties#IGNITE_USE_TYPED_ARRAYS}. */
+ private static boolean USE_TYPED_ARRAYS =
+ IgniteSystemProperties.getBoolean(IGNITE_USE_TYPED_ARRAYS,
DFLT_IGNITE_USE_TYPED_ARRAYS);
+
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /** Context. */
+ @GridDirectTransient
+ @GridToStringExclude
+ private BinaryContext ctx;
+
+ /** Type ID. */
+ private int compTypeId;
+
+ /** Type class name. */
+ @Nullable private String compClsName;
+
+ /** Values. */
+ @GridToStringInclude(sensitive = true)
+ private Object[] arr;
+
+ /**
+ * {@link Externalizable} support.
+ */
+ public BinaryArray() {
+ // No-op.
+ }
+
+ /**
+ * @param ctx Context.
+ * @param compTypeId Component type id.
+ * @param compClsName Component class name.
+ * @param arr Array.
+ */
+ public BinaryArray(BinaryContext ctx, int compTypeId, @Nullable String
compClsName, Object[] arr) {
+ this.ctx = ctx;
+ this.compTypeId = compTypeId;
+ this.compClsName = compClsName;
+ this.arr = arr;
+ }
+
+ /** {@inheritDoc} */
+ @Override public BinaryType type() throws BinaryObjectException {
+ return BinaryUtils.typeProxy(ctx, this);
+ }
+
+ /** {@inheritDoc} */
+ @Override public @Nullable BinaryType rawType() throws
BinaryObjectException {
+ return BinaryUtils.type(ctx, this);
+ }
+
+ /** {@inheritDoc} */
+ @Override public <T> T deserialize() throws BinaryObjectException {
+ return (T)deserialize(null);
+ }
+
+ /** {@inheritDoc} */
+ @Override public <T> T deserialize(ClassLoader ldr) throws
BinaryObjectException {
+ ClassLoader resolveLdr = ldr == null ?
ctx.configuration().getClassLoader() : ldr;
+
+ if (ldr != null)
+ GridBinaryMarshaller.USE_CACHE.set(Boolean.FALSE);
+
+ try {
+ Class<?> compType = BinaryUtils.resolveClass(ctx, compTypeId,
compClsName, resolveLdr, false);
+
+ Object[] res = Object.class == compType ? arr :
(Object[])Array.newInstance(compType, arr.length);
Review comment:
This makes `BinaryArray` mutable. For example:
```
Object[] val = new Object[] {new TestClass1()};
BinaryArray binVal = grid(0).binary().toBinary(val);
assertTrue(binVal.array()[0] instanceof BinaryObject);
binVal.deserialize();
assertTrue(binVal.array()[0] instanceof BinaryObject);
```
This code will fail on the second `assertTrue`. After deserialization,
`BinaryArray` contains some not binary types. Is it expected?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]