in java/fury-core/src/main/java/org/apache/fury/serializer/collection/AbstractMapSerializer.java [344:448]
private Entry writeJavaChunkGeneric(
TypeResolver classResolver,
Generics generics,
GenericType genericType,
MemoryBuffer buffer,
Entry<Object, Object> entry,
Iterator<Entry<Object, Object>> iterator) {
// type parameters count for `Map field` will be 0;
// type parameters count for `SubMap<V> field` which SubMap is
// `SubMap<V> implements Map<String, V>` will be 1;
if (genericType.getTypeParametersCount() < 2) {
genericType = getKVGenericType(genericType);
}
GenericType keyGenericType = genericType.getTypeParameter0();
GenericType valueGenericType = genericType.getTypeParameter1();
if (keyGenericType == objType && valueGenericType == objType) {
return writeJavaChunk(classResolver, buffer, entry, iterator, null, null);
}
// Can't avoid push generics repeatedly in loop by stack depth, because push two
// generic type changed generics stack top, which is depth index, update stack top
// and depth will have some cost too.
// Stack depth to avoid push generics repeatedly in loop.
// Note push two generic type changed generics stack top, which is depth index,
// stack top should be updated when using for serialization k/v.
// int depth = fury.getDepth();
// // depth + 1 to leave a slot for value generics, otherwise value generics will
// // be overwritten by nested key generics.
// fury.setDepth(depth + 1);
// generics.pushGenericType(keyGenericType);
// fury.setDepth(depth);
// generics.pushGenericType(valueGenericType);
boolean keyGenericTypeFinal = keyGenericType.isMonomorphic();
boolean valueGenericTypeFinal = valueGenericType.isMonomorphic();
Object key = entry.getKey();
Object value = entry.getValue();
Class keyType = key.getClass();
Class valueType = value.getClass();
Serializer keySerializer, valueSerializer;
// place holder for chunk header and size.
buffer.writeInt16((short) -1);
int chunkSizeOffset = buffer.writerIndex() - 1;
int chunkHeader = 0;
// noinspection Duplicates
if (keyGenericTypeFinal) {
chunkHeader |= KEY_DECL_TYPE;
keySerializer = keyGenericType.getSerializer(classResolver);
} else {
keySerializer = writeKeyClassInfo(classResolver, keyType, buffer);
}
if (valueGenericTypeFinal) {
chunkHeader |= VALUE_DECL_TYPE;
valueSerializer = valueGenericType.getSerializer(classResolver);
} else {
valueSerializer = writeValueClassInfo(classResolver, valueType, buffer);
}
boolean keyWriteRef = keySerializer.needToWriteRef();
if (keyWriteRef) {
chunkHeader |= TRACKING_KEY_REF;
}
boolean valueWriteRef = valueSerializer.needToWriteRef();
if (valueWriteRef) {
chunkHeader |= TRACKING_VALUE_REF;
}
buffer.putByte(chunkSizeOffset - 1, (byte) chunkHeader);
RefResolver refResolver = fury.getRefResolver();
// Use int to make chunk size representable for 0~255 instead of 0~127.
int chunkSize = 0;
while (true) {
if (key == null
|| value == null
|| (key.getClass() != keyType)
|| (value.getClass() != valueType)) {
break;
}
generics.pushGenericType(keyGenericType);
if (!keyWriteRef || !refResolver.writeRefOrNull(buffer, key)) {
fury.incDepth(1);
binding.write(buffer, keySerializer, key);
fury.incDepth(-1);
}
generics.popGenericType();
generics.pushGenericType(valueGenericType);
if (!valueWriteRef || !refResolver.writeRefOrNull(buffer, value)) {
fury.incDepth(1);
binding.write(buffer, valueSerializer, value);
fury.incDepth(-1);
}
generics.popGenericType();
++chunkSize;
// noinspection Duplicates
if (iterator.hasNext()) {
entry = iterator.next();
key = entry.getKey();
value = entry.getValue();
} else {
entry = null;
break;
}
if (chunkSize == MAX_CHUNK_SIZE) {
break;
}
}
buffer.putByte(chunkSizeOffset, (byte) chunkSize);
return entry;
}