From 5cb676aa1043c6b626dade681f20fb12bcdb9fd3 Mon Sep 17 00:00:00 2001 From: xuedonglxd Date: Fri, 29 Apr 2022 15:00:16 +0800 Subject: [PATCH] #894 Enable TaggedFieldSerializer to skip null fields (only works with chunked encoding) --- .../serializers/TaggedFieldSerializer.java | 40 +++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/src/com/esotericsoftware/kryo/serializers/TaggedFieldSerializer.java b/src/com/esotericsoftware/kryo/serializers/TaggedFieldSerializer.java index 18a760b7d..ce337bce8 100644 --- a/src/com/esotericsoftware/kryo/serializers/TaggedFieldSerializer.java +++ b/src/com/esotericsoftware/kryo/serializers/TaggedFieldSerializer.java @@ -38,6 +38,9 @@ import java.lang.annotation.Target; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; /** Serializes objects using direct field assignment for fields that have a @Tag(int) annotation, providing backward * compatibility and optional forward compatibility. This means fields can be added or renamed and optionally removed without @@ -118,12 +121,24 @@ public void write (Kryo kryo, Output output, T object) { } int pop = pushTypeVariables(); - CachedField[] writeTags = this.writeTags; + + boolean chunked = config.chunked, readUnknownTagData = config.readUnknownTagData, skipNullFields = config.skipNullFields; + + if (chunked && skipNullFields) { + //filter fields with null values + List list = Arrays.stream(writeTags) + .filter(field -> !isNullField(field,object)).collect(Collectors.toList()); + writeTags = new CachedField[list.size()]; + for (int i = 0; i < list.size(); i++) { + writeTags[i] = list.get(i); + } + } + output.writeVarInt(writeTags.length + 1, true); + writeHeader(kryo, output, object); - boolean chunked = config.chunked, readUnknownTagData = config.readUnknownTagData; Output fieldOutput; OutputChunked outputChunked = null; if (chunked) @@ -163,6 +178,17 @@ public void write (Kryo kryo, Output output, T object) { popTypeVariables(pop); } + private boolean isNullField(CachedField cachedField, Object target) { + try { + if (cachedField.getField().get(target) != null) { + return false; + } + } catch (Exception e) { + //this should not happen because the fields should be accessible + } + return true; + } + /** Can be overidden to write data needed for {@link #create(Kryo, Input, Class)}. The default implementation does nothing. */ protected void writeHeader (Kryo kryo, Output output, T object) { } @@ -252,7 +278,7 @@ public TaggedFieldSerializerConfig getTaggedFieldSerializerConfig () { /** Configuration for TaggedFieldSerializer instances. */ public static class TaggedFieldSerializerConfig extends FieldSerializerConfig { - boolean readUnknownTagData, chunked; + boolean readUnknownTagData, chunked, skipNullFields; int chunkSize = 1024; public TaggedFieldSerializerConfig clone () { @@ -291,6 +317,14 @@ public boolean getChunkedEncoding () { return chunked; } + public boolean isSkipNullFields() { + return skipNullFields; + } + + public void setSkipNullFields(boolean skipNullFields) { + this.skipNullFields = skipNullFields; + } + /** The maximum size of each chunk for chunked encoding. Default is 1024. */ public void setChunkSize (int chunkSize) { this.chunkSize = chunkSize;