Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
39f11fa
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 22, 2026
3f15eb9
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 22, 2026
ab1ff1a
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 22, 2026
45720ab
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 23, 2026
3770237
Merge branch 'master' into IGNITE-27641
nizhikov Jan 23, 2026
bc0e9f0
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 23, 2026
6959ecc
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 23, 2026
308ddd6
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 23, 2026
baa6d7b
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 23, 2026
d58705f
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 24, 2026
2f51d3d
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 24, 2026
bea02ab
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 24, 2026
1913eca
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 25, 2026
9d9e5b8
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 26, 2026
c78d3ec
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 26, 2026
bcb334f
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 26, 2026
14338c1
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 27, 2026
5bc0e15
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 27, 2026
3945a26
Merge branch 'IGNITE-27641' into IGNITE-27641-2
nizhikov Jan 27, 2026
2f65874
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 27, 2026
6d9b2d2
Merge branch 'master' into IGNITE-27641-2
nizhikov Jan 29, 2026
336babe
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 29, 2026
2f615b4
Merge branch 'master' into IGNITE-27641-2
nizhikov Jan 30, 2026
0fa3a41
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Jan 30, 2026
46ba939
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Feb 2, 2026
d3b5fb8
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Feb 2, 2026
4273d96
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Feb 2, 2026
daf82fb
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Feb 2, 2026
f8bcd75
Merge branch 'master' into IGNITE-27709
nizhikov Feb 2, 2026
51be989
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Feb 2, 2026
5fd25f7
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Feb 2, 2026
132bcc2
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Feb 2, 2026
fc043fd
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Feb 2, 2026
19d758a
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Feb 3, 2026
7a4c425
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Feb 3, 2026
4535fd9
Merge branch 'master' into IGNITE-27709
nizhikov Feb 3, 2026
52f1619
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Feb 3, 2026
aa5fe15
IGNITE-27641 Generate serdes code for IgniteDataTransferObject
nizhikov Feb 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
import java.util.function.Function;
import javax.annotation.processing.FilerException;
Expand All @@ -44,6 +47,7 @@
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
Expand All @@ -56,6 +60,7 @@
import static org.apache.ignite.internal.MessageSerializerGenerator.TAB;
import static org.apache.ignite.internal.MessageSerializerGenerator.enumType;
import static org.apache.ignite.internal.MessageSerializerGenerator.identicalFileIsAlreadyGenerated;
import static org.apache.ignite.internal.idto.IgniteDataTransferObjectProcessor.DTO_CLASS;

/**
* Generates serializer class for given {@code IgniteDataTransferObject} extension.
Expand All @@ -66,13 +71,21 @@ public class IDTOSerializerGenerator {
/** Serializer interface. */
public static final String DTO_SERDES_INTERFACE = "org.apache.ignite.internal.dto.IgniteDataTransferObjectSerializer";

/** Class javadoc */
/** Class javadoc. */
static final String CLS_JAVADOC = "/** " + NL +
" * This class is generated automatically." + NL +
" *" + NL +
" * @see org.apache.ignite.internal.dto.IgniteDataTransferObject" + NL +
" */";

/** */
private static final IgniteBiTuple<String, String> OBJECT_SERDES =
F.t("out.writeObject(obj.${f});", "obj.${f} = (${c})in.readObject();");

/** */
private static final IgniteBiTuple<String, String> STR_STR_MAP =
F.t("U.writeStringMap(out, obj.${f});", "obj.${f} = U.readStringMap(in);");

/** Type name to write/read code for the type. */
private static final Map<String, IgniteBiTuple<String, String>> TYPE_SERDES = new HashMap<>();

Expand All @@ -85,22 +98,34 @@ public class IDTOSerializerGenerator {
TYPE_SERDES.put(float.class.getName(), F.t("out.writeFloat(obj.${f});", "obj.${f} = in.readFloat();"));
TYPE_SERDES.put(double.class.getName(), F.t("out.writeDouble(obj.${f});", "obj.${f} = in.readDouble();"));

IgniteBiTuple<String, String> objSerdes = F.t("out.writeObject(obj.${f});", "obj.${f} = (${c})in.readObject();");

TYPE_SERDES.put(Boolean.class.getName(), objSerdes);
TYPE_SERDES.put(Byte.class.getName(), objSerdes);
TYPE_SERDES.put(Short.class.getName(), objSerdes);
TYPE_SERDES.put(Integer.class.getName(), objSerdes);
TYPE_SERDES.put(Long.class.getName(), objSerdes);
TYPE_SERDES.put(Float.class.getName(), objSerdes);
TYPE_SERDES.put(Double.class.getName(), objSerdes);
TYPE_SERDES.put(Boolean.class.getName(), OBJECT_SERDES);
TYPE_SERDES.put(Byte.class.getName(), OBJECT_SERDES);
TYPE_SERDES.put(Short.class.getName(), OBJECT_SERDES);
TYPE_SERDES.put(Integer.class.getName(), OBJECT_SERDES);
TYPE_SERDES.put(Long.class.getName(), OBJECT_SERDES);
TYPE_SERDES.put(Float.class.getName(), OBJECT_SERDES);
TYPE_SERDES.put(Double.class.getName(), OBJECT_SERDES);
TYPE_SERDES.put(Throwable.class.getName(), OBJECT_SERDES);
TYPE_SERDES.put(Exception.class.getName(), OBJECT_SERDES);
TYPE_SERDES.put(Object.class.getName(), OBJECT_SERDES);

TYPE_SERDES.put(String.class.getName(), F.t("U.writeString(out, obj.${f});", "obj.${f} = U.readString(in);"));
TYPE_SERDES.put(UUID.class.getName(), F.t("U.writeUuid(out, obj.${f});", "obj.${f} = U.readUuid(in);"));
TYPE_SERDES.put("org.apache.ignite.lang.IgniteUuid", F.t("U.writeIgniteUuid(out, obj.${f});", "obj.${f} = U.readIgniteUuid(in);"));
TYPE_SERDES.put("org.apache.ignite.internal.processors.cache.version.GridCacheVersion", objSerdes);

TYPE_SERDES.put("org.apache.ignite.internal.processors.cache.version.GridCacheVersion", OBJECT_SERDES);
TYPE_SERDES.put("org.apache.ignite.lang.IgniteProductVersion", OBJECT_SERDES);
TYPE_SERDES.put("org.apache.ignite.internal.binary.BinaryMetadata", OBJECT_SERDES);
TYPE_SERDES.put("org.apache.ignite.internal.management.cache.PartitionKey", OBJECT_SERDES);
TYPE_SERDES.put("org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion", OBJECT_SERDES);
TYPE_SERDES.put("org.apache.ignite.cache.CacheMode",
F.t("out.writeByte(CacheMode.toCode(obj.${f}));", "obj.${f} = CacheMode.fromCode(in.readByte());"));

TYPE_SERDES.put(TreeMap.class.getName(), F.t("U.writeMap(out, obj.${f});", "obj.${f} = U.readTreeMap(in);"));
Copy link
Contributor

@anton-vinogradov anton-vinogradov Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about to write classname or specify type at annotation or smth similar instead of changing the type of the field to TreeMap?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having field type as TreeMap is enough

TYPE_SERDES.put(LinkedHashMap.class.getName(), F.t("U.writeMap(out, obj.${f});", "obj.${f} = U.readLinkedMap(in);"));
TYPE_SERDES.put(Map.class.getName(), F.t("U.writeMap(out, obj.${f});", "obj.${f} = U.readMap(in);"));
TYPE_SERDES.put(Collection.class.getName(), F.t("U.writeCollection(out, obj.${f});", "obj.${f} = U.readCollection(in);"));
TYPE_SERDES.put(List.class.getName(), F.t("U.writeCollection(out, obj.${f});", "obj.${f} = U.readList(in);"));
TYPE_SERDES.put(Set.class.getName(), F.t("U.writeCollection(out, obj.${f});", "obj.${f} = U.readSet(in);"));
}

/** Write/Read code for enum. */
Expand Down Expand Up @@ -295,21 +320,50 @@ private List<String> fieldsSerdes(
List<VariableElement> flds,
Function<IgniteBiTuple<String, String>, String> lineProvider
) {
TypeMirror dtoCls = env.getElementUtils().getTypeElement(DTO_CLASS).asType();

List<String> code = new ArrayList<>();

for (VariableElement fld : flds) {
TypeMirror type = fld.asType();
TypeMirror comp = null;

IgniteBiTuple<String, String> serDes;
IgniteBiTuple<String, String> serDes = null;

if (type.getKind() == TypeKind.ARRAY) {
if (env.getTypeUtils().isAssignable(type, dtoCls))
serDes = OBJECT_SERDES;
else if (type.getKind() == TypeKind.TYPEVAR)
serDes = F.t("out.writeObject(obj.${f});", "obj.${f} = in.readObject();");
else if (type.getKind() == TypeKind.ARRAY) {
comp = ((ArrayType)type).getComponentType();

serDes = enumType(env, comp) ? OBJ_ARRAY_SERDES : ARRAY_TYPE_SERDES.get(className(comp));
serDes = ARRAY_TYPE_SERDES.get(className(comp));

if (serDes == null && enumType(env, comp))
serDes = OBJ_ARRAY_SERDES;
}
else {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets use elseif instead and check at final else that there is no enexpected type.

if (className(type).equals(Map.class.getName())) {
TypeMirror strCls = env.getElementUtils().getTypeElement(String.class.getName()).asType();

DeclaredType dt = (DeclaredType)type;

List<? extends TypeMirror> ta = dt.getTypeArguments();

if (ta.size() == 2
&& env.getTypeUtils().isAssignable(ta.get(0), strCls)
&& env.getTypeUtils().isAssignable(ta.get(1), strCls)) {
serDes = STR_STR_MAP;
}
}

if (serDes == null) {
serDes = TYPE_SERDES.get(className(type));

if (serDes == null && enumType(env, type))
serDes = ENUM_SERDES;
}
}
else
serDes = enumType(env, type) ? ENUM_SERDES : TYPE_SERDES.get(className(type));

if (serDes != null) {
String pattern = lineProvider.apply(serDes);
Expand Down Expand Up @@ -351,6 +405,12 @@ private List<VariableElement> fields(TypeElement type) {
/** @return FQN of {@code comp}. */
private static String className(TypeMirror comp) {
String n = comp.toString();

int spaceIdx = n.indexOf(' ');

if (spaceIdx != -1)
n = n.substring(spaceIdx + 1);

int genIdx = n.indexOf('<');

return genIdx == -1 ? n : n.substring(0, genIdx);
Expand All @@ -372,7 +432,7 @@ private String simpleClassName(TypeMirror type) {

String fqn = className(type);

if (!fqn.startsWith("java.lang"))
if (!fqn.startsWith("java.lang") && type.getKind() != TypeKind.TYPEVAR)
imports.add(fqn);

return simpleName(fqn);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
Expand Down Expand Up @@ -62,23 +61,32 @@ public class IgniteDataTransferObjectProcessor extends AbstractProcessor {
/** Package for serializers. */
private static final String FACTORY_PKG_NAME = "org.apache.ignite.internal.codegen.idto";

/** Base class that every dto must extend. */
private static final String DTO_CLASS = "org.apache.ignite.internal.dto.IgniteDataTransferObject";

/**
* Annotation used in management commands.
* For now, we restrict set of generated serdes to all management commands argument classes.
* Because, they strictly follows Ignite codestyle convention.
* Providing support of all other inheritor of {@code IgniteDataTransferObject} is matter of following improvements.
*/
private static final String ARG_ANNOTATION = "org.apache.ignite.internal.management.api.Argument";
/** Base class that every dto must extends. */
static final String DTO_CLASS = "org.apache.ignite.internal.dto.IgniteDataTransferObject";

/** Factory class name. */
public static final String FACTORY_CLASS = "IDTOSerializerFactory";

/** Generated classes. */
private final Map<TypeElement, String> genSerDes = new HashMap<>();

/** Currently unsupported classes. */
private static final Set<String> UNSUPPORTED = Set.of(
"org.apache.ignite.internal.management.baseline.BaselineNode",
"org.apache.ignite.internal.processors.cache.CacheMetricsSnapshot",
"org.apache.ignite.internal.commandline.cache.check_indexes_inline_size.CheckIndexInlineSizesResult",
"org.apache.ignite.internal.management.cache.ContentionJobResult",
"org.apache.ignite.internal.processors.metastorage.persistence.DistributedMetaStorageHistoryItem",
"org.apache.ignite.internal.management.tx.TxInfo",
"org.apache.ignite.internal.management.encryption.ReencryptionSuspendTask.ReencryptionSuspendResumeJobResult",
"org.apache.ignite.internal.management.encryption.ReencryptionStatusTask.ReencryptionStatusResult",
"org.apache.ignite.internal.management.encryption.EncryptionKeyIdsTask.EncryptionKeyIdsResult",
"org.apache.ignite.internal.management.cache.IndexForceRebuildTaskRes",
"org.apache.ignite.internal.management.cache.IndexRebuildStatusInfoContainer",
"org.apache.ignite.internal.visor.VisorTaskResult",
"org.apache.ignite.internal.visor.VisorTaskArgument"
);

/**
* Processes all classes extending the {@code IgniteDataTransferObject} and generates corresponding serializer code.
*/
Expand Down Expand Up @@ -107,28 +115,27 @@ private void generateSingle(Element el) {
return;

TypeMirror dtoCls = processingEnv.getElementUtils().getTypeElement(DTO_CLASS).asType();
TypeMirror argAnnotation = processingEnv.getElementUtils().getTypeElement(ARG_ANNOTATION).asType();

TypeElement clazz = (TypeElement)el;

// Generate code for inner classes.
clazz.getEnclosedElements().forEach(this::generateSingle);

if (UNSUPPORTED.contains(clazz.getQualifiedName().toString()))
return;

if (!processingEnv.getTypeUtils().isAssignable(clazz.asType(), dtoCls))
return;

if (clazz.getModifiers().contains(Modifier.ABSTRACT))
return;

if (!clazz.getModifiers().contains(Modifier.PUBLIC))
if (clazz.getModifiers().contains(Modifier.PRIVATE) && clazz.getModifiers().contains(Modifier.PROTECTED))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about to use some annotation instead of "package field" mark?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I don't understand the question

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now you're using "package field" mark as a marker that field shoul be serialized. Let's use annotation instead.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are commenting code part thats filter out classes, not fields.
Can you, please, clarify the question and proposal.

return;

if (clazz.getNestingKind() != NestingKind.TOP_LEVEL && clazz.getNestingKind() != NestingKind.MEMBER)
return;

if (!hasArgumentFields(clazz, argAnnotation))
return;

try {
IDTOSerializerGenerator gen = new IDTOSerializerGenerator(processingEnv, clazz);

Expand Down Expand Up @@ -364,27 +371,4 @@ private void serializer(Writer writer) throws IOException {
writer.write("}");
writer.write(NL);
}

/**
* @param type Type to analyze.
* @param argAnnotation Annotation to find.
* @return {@code True} if type has fields annotated with the {@code argAnnotation}, {@code false} otherwise.
*/
private boolean hasArgumentFields(TypeElement type, TypeMirror argAnnotation) {
while (type != null) {
for (Element el: type.getEnclosedElements()) {
if (el.getKind() != ElementKind.FIELD)
continue;

for (AnnotationMirror am : el.getAnnotationMirrors()) {
if (am.getAnnotationType().equals(argAnnotation))
return true;
}
}

type = (TypeElement)processingEnv.getTypeUtils().asElement(type.getSuperclass());
}

return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1863,7 +1863,7 @@ else if (!f.isAnnotationPresent(GridToStringExclude.class) &&
/** @return {@code True} if field should be added. */
private static boolean addField(Field f, Class<?> type) {
// Include only private non-static
return Modifier.isPrivate(f.getModifiers()) && !Modifier.isStatic(f.getModifiers()) &&
return !Modifier.isStatic(f.getModifiers()) &&
// No direct objects & serializable.
Object.class != type &&
Serializable.class != type &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
package org.apache.ignite.internal.cache.query.index.sorted;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
Expand Down Expand Up @@ -76,25 +73,25 @@ public class DurableBackgroundCleanupIndexTreeTaskV2 extends IgniteDataTransferO
@Nullable private transient volatile IgniteLogger log;

/** Unique id. */
private String uid;
String uid;

/** Cache group name. */
@Nullable private String grpName;
@Nullable String grpName;

/** Cache name. */
private String cacheName;
String cacheName;

/** Index name. */
private String idxName;
String idxName;

/** Old name of underlying index tree name. */
private String oldTreeName;
String oldTreeName;

/** New name of underlying index tree name. */
private String newTreeName;
String newTreeName;

/** Number of segments. */
private int segments;
int segments;

/** Need to rename index root pages. */
private transient volatile boolean needToRen;
Expand Down Expand Up @@ -153,28 +150,6 @@ public DurableBackgroundCleanupIndexTreeTaskV2() {
// No-op.
}

/** {@inheritDoc} */
@Override protected void writeExternalData(ObjectOutput out) throws IOException {
U.writeLongString(out, uid);
U.writeLongString(out, grpName);
U.writeLongString(out, cacheName);
U.writeLongString(out, idxName);
U.writeLongString(out, oldTreeName);
U.writeLongString(out, newTreeName);
out.writeInt(segments);
}

/** {@inheritDoc} */
@Override protected void readExternalData(ObjectInput in) throws IOException, ClassNotFoundException {
uid = U.readLongString(in);
grpName = U.readLongString(in);
cacheName = U.readLongString(in);
idxName = U.readLongString(in);
oldTreeName = U.readLongString(in);
newTreeName = U.readLongString(in);
segments = in.readInt();
}

/** {@inheritDoc} */
@Override public String name() {
return "drop-sql-index-" + cacheName + "-" + idxName + "-" + uid;
Expand Down
Loading
Loading