-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature] Add Serialization Optimization for Primitive Collection Types #2386
base: bmarcaurele/small-conjure-collections-refactor
Are you sure you want to change the base?
[Feature] Add Serialization Optimization for Primitive Collection Types #2386
Conversation
conjure-lib/src/main/java/com/palantir/conjure/java/lib/internal/ConjureDoubleList.java
Outdated
Show resolved
Hide resolved
conjure-lib/src/main/java/com/palantir/conjure/java/lib/internal/ConjureSafeLongList.java
Outdated
Show resolved
Hide resolved
1fec024
to
b6196ea
Compare
conjure-lib/src/test/java/com/palantir/conjure/java/lib/internal/ConjureCollectionsTest.java
Outdated
Show resolved
Hide resolved
conjure-lib/src/main/java/com/palantir/conjure/java/lib/internal/ConjureDoubleList.java
Outdated
Show resolved
Hide resolved
a76bb0d
to
505cc4c
Compare
import org.eclipse.collections.impl.utility.Iterate; | ||
|
||
/** | ||
* ConjureDoubleList is a boxed list wrapper for the eclipse-collections DoubleArrayList. In eclipse-collections 12, | ||
* a BoxedMutableDoubleList will be released. Once available, ConjureDoubleList should be replaced with that. | ||
*/ | ||
final class ConjureDoubleList extends AbstractList<Double> implements RandomAccess { | ||
private final DoubleArrayList delegate; | ||
private final MutableDoubleList delegate; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing this type so that I can wrap both DoubleArrayList
and UnmodifiableDoubleList
which share this interface as the lowest common denominator.
import org.eclipse.collections.impl.utility.Iterate; | ||
|
||
/** | ||
* ConjureIntegerList is a boxed list wrapper for the eclipse-collections IntArrayList. In eclipse-collections 12, | ||
* a BoxedMutableIntList will be released. Once available, ConjureIntegerList should be replaced with that. | ||
*/ | ||
final class ConjureIntegerList extends AbstractList<Integer> implements RandomAccess { | ||
private final IntArrayList delegate; | ||
private final MutableIntList delegate; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import org.eclipse.collections.impl.utility.Iterate; | ||
|
||
/** | ||
* ConjureSafeLongList is a boxed list wrapper for the eclipse-collections LongArrayList. This handles boxing/unboxing | ||
* with SafeLongs. | ||
*/ | ||
final class ConjureSafeLongList extends AbstractList<SafeLong> implements RandomAccess { | ||
private final LongArrayList delegate; | ||
private final MutableLongList delegate; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// This is a serialization optimization that avoids boxing, but does copy | ||
@JsonValue | ||
double[] jacksonSerialize() { | ||
return delegate.toArray(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is how we avoid boxing out the door (I checked the Jackson code paths manually, it does infact operate on the array), while also respecting the various Jackson flags we use like excludeEmptyCollections
. It does make a copy, but implementing a version that avoided this copy was very complex as it required leaking details of various Jackson settings.
// This is a serialization optimization that avoids boxing, but does copy | ||
@JsonValue | ||
int[] jacksonSerialize() { | ||
return delegate.toArray(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// This is a serialization optimization that avoids boxing, but does copy | ||
@JsonValue | ||
long[] jacksonSerialize() { | ||
return delegate.toArray(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
505cc4c
to
8afd7d8
Compare
@@ -259,7 +260,7 @@ private static MethodSpec createConstructor(Collection<EnrichedField> fields, Co | |||
// is private and necessarily called from the builder, which does its own defensive copying. | |||
if (field.conjureDef().getType().accept(TypeVisitor.IS_LIST)) { | |||
// TODO(melliot): contribute a fix to JavaPoet that parses $T correctly for a JavaPoet FieldSpec | |||
body.addStatement("this.$1N = $2T.unmodifiableList($1N)", spec, Collections.class); | |||
body.addStatement("this.$1N = $2T.unmodifiableList($1N)", spec, ConjureCollections.class); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pulled this out in to a separate PR so this one can continue to focus on the optimizations: #2409
8afd7d8
to
8376624
Compare
1eecccf
to
74269fc
Compare
8376624
to
42e78f4
Compare
Before this PR
When Jackson attempted to serialize a primitive collection type, e.g.
ConjureDoubleList
, it utilized Jackon's default serializers, specificallyIndexedListSerializer
. This makes sense when you remember thatConjureDoubleList
does not have an implemented serializer, so at best its going to be treated like List at time of serialization. This causes unnecessary boxing no matter how optimally you this collection stores the primitive types. You can see evidence of these points in the debugging screenshot below:After this PR
Adds serialization paths that avoid boxing and directly leverage Jackson primitive serialization routines.
I purposely didn't implement this feature forThis has been removed #2390ConjureBooleanList
because it does not have a simple serialized format that benefits from primitive optimization. i.e. it expands a single bit out totrue
orfalse
over the wire. Frankly, this type feels like it was added for completeness and not for usefulness. A denseboolean[]
is abstractly a bit mask and if that is the intent should have its own type. I think the existence of this class is just maintenance overhead at this point.Possible downsides?
Creates an alternative path for serialization that needs to match the default serialization paths.