Skip to content
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

Remove specialization-related conditional logic from PojoCodecImpl by introducing LazyPropertyModelCodec.NeedsSpecializationCodec #1136

Conversation

stIncMale
Copy link
Member

This PR moves some of the conditional logic from PojoCodecImpl under the rug, thus allegedly simplifying PojoCodecImpl, but not the POJO codec implementation overall.

I still have no idea about the following:

  • What "specialization" means and why it exists?
  • Why there is two "unusable" types codecs; previously it was LazyPropertyModelCodec and some instances of PojoCodecImpl, now its LazyPropertyModelCodec and all instances of NeedsSpecializationCodec?
  • Why is it so happens that NeedsSpecializationCodec is always (I judge based on the existing tests) replaced by LazyPropertyModelCodec with a usable codec instance?

JAVA-4954

…by introducing `LazyPropertyModelCodec.NeedsSpecializationCodec`

This commit moves some of the conditional logic from `PojoCodecImpl` under the rug,
thus allegedly simplifying `PojoCodecImpl`, but not the POJO codec implementation overall.

I still have no idea about the following:

- What "specialization" means and why it exists?
- Why there is two "unusable" types codecs; previously it was `LazyPropertyModelCodec` and some instances of `PojoCodecImpl`,
now its `LazyPropertyModelCodec` and all instances of `NeedsSpecializationCodec`?
- Why is it so happens that `NeedsSpecializationCodec` is always (I judge based on the existing tests) replaced by `LazyPropertyModelCodec` with a usable codec instance?

JAVA-4954
@stIncMale stIncMale requested a review from jyemin June 6, 2023 01:05
@stIncMale stIncMale self-assigned this Jun 6, 2023
@stIncMale
Copy link
Member Author

@jyemin I think that this change makes the code a bit simpler. Unfortunately, it does not result in having any new step towards drastically simplifying the POJO codec implementation.

@jyemin jyemin requested a review from rozza June 6, 2023 16:53
Copy link
Member

@rozza rozza left a comment

Choose a reason for hiding this comment

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

Great questions - I had to dive through the code to understand it more.

  • What "specialization" means and why it exists?

Originally, the CodecRegistry could only handle classes eg: registry.get(MyPojo.class). "specialization" just means setting the concrete types parameters for a POJO's property.

public final class NestedSelfReferentialGenericHolderModel {
    private NestedSelfReferentialGenericModel<Boolean, Long, Double> nested;
}

public final class NestedSelfReferentialGenericModel<T, V, Z> {
    private SelfReferentialGenericModel<T, V> selfRef1;
    private SelfReferentialGenericModel<T, Z> selfRef2;
}

public final class SelfReferentialGenericModel<T, V> {
    private T t;
    private V v;
    private SelfReferentialGenericModel<V, T> child;
}

With the above POJOs, we have enough data to model all the POJOs for the properties. However, we have some cyclical considerations as SelfReferentialGenericModel is self referential.
Specialization is also used to handle the SelfReferentialGenericModel codec and its appropriate types when set per property.

  • Why there is two "unusable" types codecs; previously it was LazyPropertyModelCodec and some instances of PojoCodecImpl, now its LazyPropertyModelCodec and all instances of NeedsSpecializationCodec?
  • LazyPropertyModelCodec just defers the handling of a property's generic types until its actually used to decode/encode data. Hence breaking any cycles.
  • NeedsSpecializationCodec means we have no type data at that point in time. This happens when a POJO containing type parameters is used with codecRegistry.get(clazz).
  • Why is it so happens that NeedsSpecializationCodec is always (I judge based on the existing tests) replaced by LazyPropertyModelCodec with a usable codec instance?

Nearly always ;) There are two causes; direct use like in testCannotEncodeUnspecializedClasses Or via the FallbackPropertyCodecProvider.
(This would be the place to actually call the registry with the TypeArguments as they are effectively lost after this point - we should open a ticket for that).

As NeedsSpecializationCodec is a PojoCodec the LazyPropertyModelCodec both creates and replaces it when calling createCodec - which has a code smell.

I like the PR - just a couple of comments

@@ -50,36 +50,28 @@
private final CodecRegistry registry;
private final PropertyCodecRegistry propertyCodecRegistry;
private final DiscriminatorLookup discriminatorLookup;
private final boolean specialized;

PojoCodecImpl(final ClassModel<T> classModel, final CodecRegistry codecRegistry,
Copy link
Member

Choose a reason for hiding this comment

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

Looks like the constructors can now be chained - ie. this one calls the below.

Copy link
Member Author

Choose a reason for hiding this comment

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

I wish ... : one of them (PojoCodecImpl(final ClassModel<T> classModel, final CodecRegistry codecRegistry, final List<PropertyCodecProvider> propertyCodecProviders, final DiscriminatorLookup discriminatorLookup)) has to give this to a new PropertyCodecRegistry, which means that this constructor can neither be called from the other one, nor the other one can call this one.

As far as I can see, only refactoring of the code around PojoCodecImpl may open up opportunities to either calling one of the constructors from the other, or getting rid of one of them. But I don't even know if such refactoring is possible, and if yes, what it will look like.

this.classModel = classModel;
this.registry = codecRegistry;
this.discriminatorLookup = discriminatorLookup;
this.propertyCodecRegistry = propertyCodecRegistry;
this.specialized = specialized;
specialize();
Copy link
Member

Choose a reason for hiding this comment

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

Can this specialize() logic now be moved into the constructor?

Copy link
Member Author

Choose a reason for hiding this comment

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

Unless we want to duplicate a bunch of code, this can only be done if one of the constructors reuses the other one, which does not seem possible.

@jyemin jyemin removed their request for review June 7, 2023 19:14
@stIncMale stIncMale requested a review from rozza June 9, 2023 02:19
Copy link
Member

@rozza rozza left a comment

Choose a reason for hiding this comment

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

LGTM

@stIncMale stIncMale merged commit 14cfcdc into mongodb:master Jun 9, 2023
@stIncMale stIncMale deleted the JAVA-4954_simplfySpecializedInPojoCodecImpl branch June 9, 2023 14:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants