This is an automated email from the ASF dual-hosted git repository.

shishkovilja pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new bc1e3d277e3 IGNITE-28767 Use Message DTO to transfer QueryEntity 
(#13236)
bc1e3d277e3 is described below

commit bc1e3d277e33d83b4df5511203c74a4f33b9743f
Author: Ilya Shishkov <[email protected]>
AuthorDate: Tue Jul 7 12:27:00 2026 +0300

    IGNITE-28767 Use Message DTO to transfer QueryEntity (#13236)
---
 .../ignite/internal/CoreMessagesProvider.java      |   8 +-
 .../internal/cache/query/QueryIndexMessage.java    |   6 +-
 .../internal/processors/query/QueryField.java      |   6 +-
 .../query/schema/message/QueryEntityExMessage.java |  88 ++++++++++
 .../query/schema/message/QueryEntityMessage.java   | 158 +++++++++++++++++
 .../schema/operation/SchemaAbstractOperation.java  |   6 +-
 .../operation/SchemaAddQueryEntityOperation.java   |  65 +++----
 .../SchemaAlterTableAddColumnOperation.java        |   3 -
 .../SchemaAlterTableDropColumnOperation.java       |   3 -
 .../operation/SchemaIndexCreateOperation.java      |   3 -
 .../schema/operation/SchemaIndexDropOperation.java |   3 -
 .../QueryEntityMessageSerializationTest.java       | 193 +++++++++++++++++++++
 .../testsuites/IgniteCacheQuerySelfTestSuite6.java |   2 +
 13 files changed, 476 insertions(+), 68 deletions(-)

diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java
index e037bd50f02..fb71225adb0 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java
@@ -218,6 +218,8 @@ import 
org.apache.ignite.internal.processors.query.h2.twostep.messages.GridQuery
 import 
org.apache.ignite.internal.processors.query.h2.twostep.messages.GridQueryNextPageResponse;
 import 
org.apache.ignite.internal.processors.query.messages.GridQueryKillRequest;
 import 
org.apache.ignite.internal.processors.query.messages.GridQueryKillResponse;
+import 
org.apache.ignite.internal.processors.query.schema.message.QueryEntityExMessage;
+import 
org.apache.ignite.internal.processors.query.schema.message.QueryEntityMessage;
 import 
org.apache.ignite.internal.processors.query.schema.message.QueryInlineSizesDataBagItem;
 import 
org.apache.ignite.internal.processors.query.schema.message.QueryProposalsDataBagItem;
 import 
org.apache.ignite.internal.processors.query.schema.message.SchemaFinishDiscoveryMessage;
@@ -589,7 +591,9 @@ public class CoreMessagesProvider extends 
AbstractMarshallableMessageFactoryProv
         withNoSchema(GridDhtTxSalvageMessage.class);
         withSchema(CacheContinuousQueryEntry.class);
         withNoSchema(QueryInlineSizesDataBagItem.class);
-        withSchema(QueryProposalsDataBagItem.class);
+        withNoSchema(QueryProposalsDataBagItem.class);
+        withNoSchema(QueryEntityMessage.class);
+        withNoSchema(QueryEntityExMessage.class);
 
         // [11200 - 11300]: Compute, distributed process messages.
         msgIdx = 11200;
@@ -644,7 +648,7 @@ public class CoreMessagesProvider extends 
AbstractMarshallableMessageFactoryProv
         withNoSchema(UserAuthenticateRequestMessage.class);
         withNoSchema(UserAuthenticateResponseMessage.class);
         withNoSchema(TcpDiscoveryAuthFailedMessage.class);
-        withSchema(AuthentificationDataBagItem.class);
+        withNoSchema(AuthentificationDataBagItem.class);
 
         // [12200 - 12300]: Binary, classloading and marshalling messages.
         msgIdx = 12200;
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/cache/query/QueryIndexMessage.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/cache/query/QueryIndexMessage.java
index c42415be029..1bdb38fc3f0 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/cache/query/QueryIndexMessage.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/cache/query/QueryIndexMessage.java
@@ -17,7 +17,6 @@
 
 package org.apache.ignite.internal.cache.query;
 
-import java.io.Serializable;
 import java.util.LinkedHashMap;
 import org.apache.ignite.cache.QueryIndex;
 import org.apache.ignite.cache.QueryIndexType;
@@ -28,10 +27,7 @@ import 
org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.plugin.extensions.communication.MessageFactory;
 
 /** Message for {@link QueryIndex}. */
-public class QueryIndexMessage implements Serializable, Message {
-    /** */
-    private static final long serialVersionUID = 0L;
-
+public class QueryIndexMessage implements Message {
     /** Index name. */
     @Order(0)
     public String name;
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryField.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryField.java
index b24e523a2b7..29659e60da3 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryField.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryField.java
@@ -17,7 +17,6 @@
 
 package org.apache.ignite.internal.processors.query;
 
-import java.io.Serializable;
 import org.apache.ignite.internal.Order;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.plugin.extensions.communication.Message;
@@ -25,10 +24,7 @@ import 
org.apache.ignite.plugin.extensions.communication.Message;
 /**
  * Query field metadata.
  */
-public class QueryField implements Serializable, Message {
-    /** */
-    private static final long serialVersionUID = 0L;
-
+public class QueryField implements Message {
     /** Field name. */
     @Order(0)
     String name;
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityExMessage.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityExMessage.java
new file mode 100644
index 00000000000..e080910dd81
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityExMessage.java
@@ -0,0 +1,88 @@
+/*
+ * 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.processors.query.schema.message;
+
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.internal.Order;
+import org.apache.ignite.internal.processors.query.QueryEntityEx;
+
+/** Message for {@link QueryEntityEx} transfer. */
+public class QueryEntityExMessage extends QueryEntityMessage {
+    /** Whether to preserve order specified by 'keyFields' or not. */
+    @Order(0)
+    boolean preserveKeysOrder;
+
+    /** Whether a primary key should be autocreated or not. */
+    @Order(1)
+    boolean implicitPk;
+
+    /** Whether absent PK parts should be filled with defaults or not. */
+    @Order(2)
+    boolean fillAbsentPKsWithDefaults;
+
+    /** INLINE_SIZE for PK index. */
+    @Order(3)
+    int pkInlineSize;
+
+    /** INLINE_SIZE for affinity field index. */
+    @Order(4)
+    int affKeyInlineSize;
+
+    /** Whether query entity was created by SQL. */
+    @Order(5)
+    boolean sql;
+
+    /** */
+    public QueryEntityExMessage() { }
+
+    /**
+     * @param qryEntity Original {@link QueryEntity}.
+     */
+    public QueryEntityExMessage(QueryEntityEx qryEntity) {
+        super(qryEntity);
+
+        preserveKeysOrder = qryEntity.isPreserveKeysOrder();
+        implicitPk = qryEntity.implicitPk();
+        fillAbsentPKsWithDefaults = qryEntity.fillAbsentPKsWithDefaults();
+
+        pkInlineSize = qryEntity.getPrimaryKeyInlineSize() != null ? 
qryEntity.getPrimaryKeyInlineSize() : -1;
+
+        affKeyInlineSize = qryEntity.getAffinityKeyInlineSize() != null ? 
qryEntity.getAffinityKeyInlineSize() : -1;
+
+        sql = qryEntity.sql();
+    }
+
+    /** {@inheritDoc} */
+    @Override public QueryEntity toEntity() {
+        QueryEntityEx qryEntity = new QueryEntityEx(entityBase());
+
+        qryEntity.setNotNullFields(notNullFields);
+        qryEntity.setPreserveKeysOrder(preserveKeysOrder);
+        qryEntity.implicitPk(implicitPk);
+        qryEntity.fillAbsentPKsWithDefaults(fillAbsentPKsWithDefaults);
+        qryEntity.sql(sql);
+
+        if (pkInlineSize != -1)
+            qryEntity.setPrimaryKeyInlineSize(pkInlineSize);
+
+        if (affKeyInlineSize != -1)
+            qryEntity.setAffinityKeyInlineSize(affKeyInlineSize);
+
+        return qryEntity;
+    }
+}
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityMessage.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityMessage.java
new file mode 100644
index 00000000000..8c6daf46cfd
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityMessage.java
@@ -0,0 +1,158 @@
+/*
+ * 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.processors.query.schema.message;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.internal.MarshallableMessage;
+import org.apache.ignite.internal.Order;
+import org.apache.ignite.internal.cache.query.QueryIndexMessage;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.marshaller.Marshaller;
+
+/**
+ * Message for {@link QueryEntity} transfer.
+ */
+public class QueryEntityMessage implements MarshallableMessage {
+    /** Key type. */
+    @Order(0)
+    String keyType;
+
+    /** Value type. */
+    @Order(1)
+    String valType;
+
+    /** Key name. */
+    @Order(2)
+    String keyFieldName;
+
+    /** Value name. */
+    @Order(3)
+    String valFieldName;
+
+    /** Fields available for query. */
+    @Order(4)
+    LinkedHashMap<String, String> fields;
+
+    /** Set of field names that belong to the key. */
+    @Order(5)
+    String[] keyFields;
+
+    /** Aliases. */
+    @Order(6)
+    Map<String, String> aliases;
+
+    /** Collection of query indexes. */
+    @Order(7)
+    Collection<QueryIndexMessage> idxs;
+
+    /** Table name. */
+    @Order(8)
+    String tableName;
+
+    /**
+     * Fields that must have non-null value.
+     * NB: Used in serde of both QueryEntity and QueryEntityEx in order to 
avoid duplication.
+     */
+    @Order(9)
+    Set<String> notNullFields;
+
+    /** Fields default values. */
+    Map<String, Object> dfltFieldValues;
+
+    /** Serialized form of {@link #dfltFieldValues}. */
+    @Order(10)
+    byte[] dfltFieldValuesBytes;
+
+    /** Precision(Maximum length) for fields. */
+    @Order(11)
+    Map<String, Integer> fieldsPrecision;
+
+    /** Scale for fields. */
+    @Order(12)
+    Map<String, Integer> fieldsScale;
+
+    /** */
+    public QueryEntityMessage() { }
+
+    /** @param qryEntity Original {@link QueryEntity}. */
+    public QueryEntityMessage(QueryEntity qryEntity) {
+        keyType = qryEntity.getKeyType();
+        valType = qryEntity.getValueType();
+
+        keyFieldName = qryEntity.getKeyFieldName();
+        valFieldName = qryEntity.getValueFieldName();
+
+        fields = qryEntity.getFields();
+        aliases = qryEntity.getAliases();
+
+        if (!F.isEmpty(qryEntity.getKeyFields()))
+            keyFields = qryEntity.getKeyFields().toArray(U.EMPTY_STRS);
+
+        if (!F.isEmpty(qryEntity.getIndexes()))
+            idxs = F.viewReadOnly(qryEntity.getIndexes(), 
QueryIndexMessage::new);
+
+        tableName = qryEntity.getTableName();
+
+        notNullFields = qryEntity.getNotNullFields();
+        dfltFieldValues = qryEntity.getDefaultFieldValues();
+        fieldsPrecision = qryEntity.getFieldsPrecision();
+        fieldsScale = qryEntity.getFieldsScale();
+    }
+
+    /** @return Original {@link QueryEntity}. */
+    public QueryEntity toEntity() {
+        return entityBase().setNotNullFields(notNullFields);
+    }
+
+    /** @return Entity without 'notNullFields.' */
+    protected QueryEntity entityBase() {
+        return new QueryEntity()
+            .setKeyType(keyType)
+            .setValueType(valType)
+            .setKeyFieldName(keyFieldName)
+            .setValueFieldName(valFieldName)
+            .setFields(fields)
+            .setKeyFields(!F.isEmpty(keyFields) ? new 
LinkedHashSet<>(List.of(keyFields)) : null)
+            .setAliases(aliases)
+            .setIndexes(!F.isEmpty(idxs) ? F.transform(idxs, 
QueryIndexMessage::queryIndex) : null)
+            .setTableName(tableName)
+            .setDefaultFieldValues(dfltFieldValues)
+            .setFieldsPrecision(fieldsPrecision)
+            .setFieldsScale(fieldsScale);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void prepareMarshal(Marshaller marsh) throws 
IgniteCheckedException {
+        if (!F.isEmpty(dfltFieldValues))
+            dfltFieldValuesBytes = U.marshal(marsh, dfltFieldValues);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void finishUnmarshal(Marshaller marsh, ClassLoader 
clsLdr) throws IgniteCheckedException {
+        if (!F.isEmpty(dfltFieldValuesBytes))
+            dfltFieldValues = U.unmarshal(marsh, dfltFieldValuesBytes, clsLdr);
+    }
+}
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaAbstractOperation.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaAbstractOperation.java
index 5264fbe2c6a..c3a83e31888 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaAbstractOperation.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaAbstractOperation.java
@@ -17,7 +17,6 @@
 
 package org.apache.ignite.internal.processors.query.schema.operation;
 
-import java.io.Serializable;
 import java.util.UUID;
 import org.apache.ignite.internal.Order;
 import org.apache.ignite.internal.util.typedef.internal.S;
@@ -26,10 +25,7 @@ import 
org.apache.ignite.plugin.extensions.communication.Message;
 /**
  * Abstract operation on schema.
  */
-public abstract class SchemaAbstractOperation implements Serializable, Message 
{
-    /** */
-    private static final long serialVersionUID = 0L;
-
+public abstract class SchemaAbstractOperation implements Message {
     /** Operation ID. */
     @Order(0)
     UUID opId;
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaAddQueryEntityOperation.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaAddQueryEntityOperation.java
index ebb23aff57e..3d700460bb7 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaAddQueryEntityOperation.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaAddQueryEntityOperation.java
@@ -19,27 +19,22 @@ package 
org.apache.ignite.internal.processors.query.schema.operation;
 
 import java.util.Collection;
 import java.util.UUID;
-import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.cache.QueryEntity;
-import org.apache.ignite.internal.MarshallableMessage;
 import org.apache.ignite.internal.Order;
-import org.apache.ignite.internal.util.typedef.internal.U;
-import org.apache.ignite.marshaller.Marshaller;
-
-/**
- * Enabling indexing on cache operation.
- */
-public class SchemaAddQueryEntityOperation extends SchemaAbstractOperation 
implements MarshallableMessage {
-    /** */
-    private static final long serialVersionUID = 0L;
+import org.apache.ignite.internal.processors.query.QueryEntityEx;
+import 
org.apache.ignite.internal.processors.query.schema.message.QueryEntityExMessage;
+import 
org.apache.ignite.internal.processors.query.schema.message.QueryEntityMessage;
+import org.apache.ignite.internal.util.typedef.F;
+
+/** Operation, which enables indexing on cache operation. */
+public class SchemaAddQueryEntityOperation extends SchemaAbstractOperation {
+    /** Query entities messages. */
+    @Order(0)
+    Collection<QueryEntityMessage> entitiesMsgs;
 
-    /** */
+    /** Original query entities. We keep them to avoid unneccessary 
conversions from messages. */
     private Collection<QueryEntity> entities;
 
-    /** Serialized form of query entities. */
-    @Order(0)
-    transient byte[] qryEntitiesBytes;
-
     /** */
     @Order(1)
     int qryParallelism;
@@ -71,42 +66,34 @@ public class SchemaAddQueryEntityOperation extends 
SchemaAbstractOperation imple
         this.entities = entities;
         this.qryParallelism = qryParallelism;
         this.sqlEscape = sqlEscape;
+
+        entitiesMsgs = F.viewReadOnly(entities, this::makeEntityMessage);
     }
 
-    /**
-     * @return Collection of query entities.
-     */
+    /** @return Collection of query entities. */
     public Collection<QueryEntity> entities() {
+        if (entities == null)
+            entities = F.transform(entitiesMsgs, QueryEntityMessage::toEntity);
+
         return entities;
     }
 
-    /**
-     * @return Query parallelism.
-     */
+    /** @return Query parallelism. */
     public int queryParallelism() {
         return qryParallelism;
     }
 
-    /**
-     * @return Sql escape flag.
-     */
+    /** @return Sql escape flag. */
     public boolean isSqlEscape() {
         return sqlEscape;
     }
 
-    /** {@inheritDoc} */
-    @Override public void prepareMarshal(Marshaller marsh) throws 
IgniteCheckedException {
-        if (entities != null)
-            qryEntitiesBytes = U.marshal(marsh, entities);
-    }
-
-    /** {@inheritDoc} */
-    @Override public void finishUnmarshal(Marshaller marsh, ClassLoader 
clsLdr) throws IgniteCheckedException {
-        if (qryEntitiesBytes != null) {
-            entities = U.unmarshal(marsh, qryEntitiesBytes, clsLdr);
-
-            qryEntitiesBytes = null;
-        }
+    /**
+     * @param qryEntity Query entity.
+     * @return The appropriate query entity message.
+     */
+    private QueryEntityMessage makeEntityMessage(QueryEntity qryEntity) {
+        return qryEntity instanceof QueryEntityEx ? new 
QueryEntityExMessage((QueryEntityEx)qryEntity)
+            : new QueryEntityMessage(qryEntity);
     }
-
 }
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaAlterTableAddColumnOperation.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaAlterTableAddColumnOperation.java
index 11d77d31c5b..481e8f26fdd 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaAlterTableAddColumnOperation.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaAlterTableAddColumnOperation.java
@@ -27,9 +27,6 @@ import org.apache.ignite.internal.util.typedef.internal.S;
  * Schema index drop operation.
  */
 public class SchemaAlterTableAddColumnOperation extends 
SchemaAbstractOperation {
-    /** */
-    private static final long serialVersionUID = 0L;
-
     /** Target table name. */
     @Order(0)
     String tblName;
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaAlterTableDropColumnOperation.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaAlterTableDropColumnOperation.java
index cf48709e921..1aca33c5717 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaAlterTableDropColumnOperation.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaAlterTableDropColumnOperation.java
@@ -26,9 +26,6 @@ import org.apache.ignite.internal.util.typedef.internal.S;
  * Schema alter table drop column operation.
  */
 public class SchemaAlterTableDropColumnOperation extends 
SchemaAbstractOperation {
-    /** */
-    private static final long serialVersionUID = 0L;
-
     /** Target table name. */
     @Order(0)
     String tblName;
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaIndexCreateOperation.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaIndexCreateOperation.java
index 056ccaae028..7dcde0c297e 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaIndexCreateOperation.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaIndexCreateOperation.java
@@ -29,9 +29,6 @@ import org.apache.ignite.internal.util.typedef.internal.S;
  * Schema index create operation.
  */
 public class SchemaIndexCreateOperation extends SchemaIndexAbstractOperation {
-    /** */
-    private static final long serialVersionUID = 0L;
-
     /** Table name. */
     @Order(0)
     String tblName;
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaIndexDropOperation.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaIndexDropOperation.java
index 6962fbb0ee5..4d0db89a638 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaIndexDropOperation.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaIndexDropOperation.java
@@ -25,9 +25,6 @@ import org.apache.ignite.internal.util.typedef.internal.S;
  * Schema index drop operation.
  */
 public class SchemaIndexDropOperation extends SchemaIndexAbstractOperation {
-    /** */
-    private static final long serialVersionUID = 0L;
-
     /** Index name. */
     @Order(0)
     String idxName;
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityMessageSerializationTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityMessageSerializationTest.java
new file mode 100644
index 00000000000..6ed6171d81a
--- /dev/null
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityMessageSerializationTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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.processors.query.schema.message;
+
+import java.io.Externalizable;
+import java.io.Serializable;
+import java.lang.reflect.Modifier;
+import java.math.BigDecimal;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.cache.QueryIndex;
+import org.apache.ignite.cache.QueryIndexType;
+import org.apache.ignite.internal.CoreMessagesProvider;
+import org.apache.ignite.internal.direct.DirectMessageReader;
+import org.apache.ignite.internal.direct.DirectMessageWriter;
+import 
org.apache.ignite.internal.managers.communication.IgniteMessageFactoryImpl;
+import org.apache.ignite.internal.processors.query.QueryEntityEx;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.marshaller.Marshaller;
+import org.apache.ignite.plugin.extensions.communication.Message;
+import org.apache.ignite.plugin.extensions.communication.MessageFactory;
+import 
org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider;
+import org.apache.ignite.plugin.extensions.communication.MessageSerializer;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+import static org.apache.ignite.marshaller.Marshallers.jdk;
+import static 
org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi.makeMessageType;
+
+/** Test for serialization round-trip of {@link QueryEntityMessage} and {@link 
QueryEntityExMessage}. */
+public class QueryEntityMessageSerializationTest extends 
GridCommonAbstractTest {
+    /** Error suffix. */
+    public static final String ERROR_SUFFIX = " count is not equal to the 
expected fields count. " +
+        "Has the number of fields in the `QueryEntity` or `QueryEntityEx` 
classes changed?";
+
+    /** */
+    private final Marshaller marsh = jdk();
+
+    /** */
+    private final MessageFactory msgFactory = new IgniteMessageFactoryImpl(
+        new MessageFactoryProvider[] {new CoreMessagesProvider(marsh, marsh, 
U.gridClassLoader())});
+
+    /** */
+    @Test
+    public void testQueryEntity() throws Exception {
+        QueryEntity entity = queryEntity();
+
+        assertEquals(entity, serializeAndDeserialize(entity, 
serializableFieldsCount(QueryEntity.class)));
+    }
+
+    /** */
+    @Test
+    public void testQueryEntityEx() throws Exception {
+        QueryEntityEx entity = queryEntityEx();
+
+        long expReadWriteCnt = serializableFieldsCount(QueryEntityEx.class) -
+            /* QueryEntityEx duplicates 'notNullFields', but 
'QueryEntityExMessage' doesn't */ 1;
+
+        QueryEntity res = serializeAndDeserialize(entity, expReadWriteCnt);
+
+        assertTrue(res instanceof QueryEntityEx);
+        assertEquals(entity, res);
+
+        // Not part of QueryEntityEx.equals(), so assert it explicitly.
+        assertEquals(entity.fillAbsentPKsWithDefaults(), 
((QueryEntityEx)res).fillAbsentPKsWithDefaults());
+    }
+
+    /**
+     * @param src Source entity.
+     * @param expReadsWritesCnt Expected count of field reads and writes.
+     *
+     * @return Entity read during a full serde round-trip.
+     */
+    private QueryEntity serializeAndDeserialize(QueryEntity src, long 
expReadsWritesCnt) {
+        QueryEntityMessage msg = src instanceof QueryEntityEx
+            ? new QueryEntityExMessage((QueryEntityEx)src) : new 
QueryEntityMessage(src);
+
+        return writeAndReadBack(msg, expReadsWritesCnt).toEntity();
+    }
+
+    /**
+     * @param cls Class of an object.
+     */
+    private long serializableFieldsCount(Class<?> cls) {
+        if (cls == Object.class)
+            return 0;
+
+        assertTrue("Not a serializable class: " + cls, 
Serializable.class.isAssignableFrom(cls));
+        assertFalse("Should not be Externalizable:" + cls, 
Externalizable.class.isAssignableFrom(cls));
+
+        return serializableFieldsCount(cls.getSuperclass()) + 
Arrays.stream(cls.getDeclaredFields())
+                .filter(f -> !Modifier.isStatic(f.getModifiers()) && 
!Modifier.isTransient(f.getModifiers()))
+                .count();
+    }
+
+    /**
+     * @param msg Message to write and read back through {@link 
DirectMessageWriter}/{@link DirectMessageReader}.
+     * @param expReadsWritesCnt Expected count of field reads and writes.
+     * @param <T> Type of Message.
+     *
+     * @return Restored message.
+     */
+    private <T extends Message> T writeAndReadBack(T msg, long 
expReadsWritesCnt) {
+        ByteBuffer buf = ByteBuffer.allocate(64 * 1024);
+
+        MessageSerializer<T> serde = 
(MessageSerializer<T>)msgFactory.serializer(msg.directType());
+
+        DirectMessageWriter writer = new DirectMessageWriter(msgFactory);
+        writer.setBuffer(buf);
+
+        assertTrue(serde.writeTo(msg, writer));
+        assertEquals("Writes" + ERROR_SUFFIX,
+            expReadsWritesCnt, writer.state());
+
+        buf.flip();
+
+        DirectMessageReader reader = new DirectMessageReader(msgFactory, null);
+        reader.setBuffer(buf);
+
+        T res = (T)msgFactory.create(makeMessageType(buf.get(), buf.get()));
+
+        assertTrue(serde.readFrom(res, reader));
+        assertEquals("Reads" + ERROR_SUFFIX,
+            expReadsWritesCnt, reader.state());
+
+        return res;
+    }
+
+    /** @return Query entity with every field populated, including non-empty 
default field values. */
+    private QueryEntity queryEntity() {
+        LinkedHashMap<String, String> fields = new LinkedHashMap<>();
+        fields.put("id", Integer.class.getName());
+        fields.put("name", String.class.getName());
+        fields.put("price", BigDecimal.class.getName());
+
+        return new QueryEntity()
+            .setKeyType(Integer.class.getName())
+            .setValueType("org.apache.ignite.Person")
+            .setKeyFieldName("id")
+            .setValueFieldName("name")
+            .setTableName("PERSON")
+            .setFields(fields)
+            .setKeyFields(Set.of("id"))
+            .setAliases(Map.of("name", "NAME_ALIAS"))
+            .setIndexes(List.of(new QueryIndex("name", 
QueryIndexType.SORTED).setInlineSize(32)))
+            .setNotNullFields(Set.of("id", "name"))
+            .setDefaultFieldValues(Map.of(
+                "name", "unknown",
+                "price", new BigDecimal("9.99"),
+                "id", 42))
+            .setFieldsPrecision(Map.of("name", 64))
+            .setFieldsScale(Map.of("price", 2));
+    }
+
+    /** @return Extended query entity with all base and extended fields 
populated. */
+    private QueryEntityEx queryEntityEx() {
+        QueryEntity base = queryEntity();
+        base.setNotNullFields(null);
+
+        QueryEntityEx entity = new QueryEntityEx(base);
+
+        // Natural QueryEntityEx: notNullFields lives only in the Ex field, 
base shadow stays null.
+        entity.setNotNullFields(Set.of("id", "name"));
+        entity.setPreserveKeysOrder(true);
+        entity.implicitPk(true);
+        entity.fillAbsentPKsWithDefaults(true);
+        entity.sql(true);
+        entity.setPrimaryKeyInlineSize(16);
+        entity.setAffinityKeyInlineSize(24);
+
+        return entity;
+    }
+}
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite6.java
 
b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite6.java
index 81047163d75..60d7e9954dd 100644
--- 
a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite6.java
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite6.java
@@ -49,6 +49,7 @@ import 
org.apache.ignite.internal.processors.query.IgniteInsertNullableDuplicate
 import 
org.apache.ignite.internal.processors.query.IgniteSqlSinglePartitionMultiParallelismTest;
 import 
org.apache.ignite.internal.processors.query.MemLeakOnSqlWithClientReconnectTest;
 import org.apache.ignite.internal.processors.query.QueryEntityAliasesTest;
+import 
org.apache.ignite.internal.processors.query.schema.message.QueryEntityMessageSerializationTest;
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
 
@@ -90,6 +91,7 @@ import org.junit.runners.Suite;
     DropTableAfterCteSqlQueryTest.class,
     LocalContinuousQueryWithNodeFailureTest.class,
     ContinuousQueryUserCodeExceptionTest.class,
+    QueryEntityMessageSerializationTest.class,
 })
 public class IgniteCacheQuerySelfTestSuite6 {
 }

Reply via email to