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

[databind#4849] Allow standard defaultTyping with EnumSet<E> #4857

Merged
merged 13 commits into from
Dec 19, 2024

Conversation

JooHyukKim
Copy link
Member

@JooHyukKim JooHyukKim commented Dec 16, 2024

resolves #4849
possible backport to 2.17

@@ -146,6 +146,11 @@ protected String _locateTypeId(JsonParser p, DeserializationContext ctxt) throws
+ClassUtil.classNameOf(_idResolver)+") returned `null`");
}
return id;
}
// [databind#4849] Since 2.18.3, Should maybe allow defaultTyping without defaultImpl if type is already known
Copy link
Member

Choose a reason for hiding this comment

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

@JooHyukKim Thinking this through, I don't think this is a proper fix, even tho it works around the specific failure here. I'll elaborate on the issue itself, but I think the problem may have been introduced by #4214 (in 2.17.0). Problem for tested case specifically is that customized DefaultTypeResolverBuilder forces addition of type information for EVERY type (for whatever reason), due to:

            @Override
            public boolean useForType(JavaType t) {
                return true;
            }

Or, it should. But while EnumSetDeserializer now expects polymorphic type id for EnumSet AND every Enum contained (... why is this desired?), I think EnumSetSerializer does not write said type id. And I guess it should.

Copy link
Member Author

@JooHyukKim JooHyukKim Dec 17, 2024

Choose a reason for hiding this comment

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

Ah okay. Let's hold this for now. Will read through ur comment later.

Copy link
Member

Choose a reason for hiding this comment

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

I committed my changes but it's very much work in progress. Too tired to continue for today, will pick up tomorrow :)

@cowtowncoder
Copy link
Member

Ok: change the fix the way I think it might work -- solves the round-trip case, but serialization is different as type ids included for enum values.
But also now fails one earlier test; will try to figure it out tomorrow.

Might also consider opposite path of sort of undoing #4214 in part, maybe -- such that contents (Enums) of EnumSet would never have type id.
But in a way that still allows 4214 case to work.

@cowtowncoder
Copy link
Member

Ah ok. So the problem wrt #4214 -- after removing expectation of deserializer expecting type id -- is this:

  1. When serializing EnumSet value declared as plain Set, regular CollectionSerializer is used, NOT EnumSetSerializer -- and CollectionSerializer includes Type Id for contents if so requested. Whereas EnumSetSerializer won't.
  2. But... Polymorphic type is still recognized as EnumSet, so type id for Collection itself is included
  3. Due to (2), correct deserializer -- EnumSetDeserializer is used. And that will now not expect Type Id (since matching EnumSetSerializer would not add it).

So. Need to think of possible way to suppress Type Id inclusion for elements even with CollectionSerializer. Might need to resort to bit of hack, even :)

@cowtowncoder cowtowncoder changed the base branch from 2.18 to 2.19 December 19, 2024 01:23
@cowtowncoder
Copy link
Member

Changes needed bit too risky for a patch, moving target to 2.19.

Copy link
Member Author

@JooHyukKim JooHyukKim left a comment

Choose a reason for hiding this comment

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

@cowtowncoder great work!

* during serialization: problem being that we can't always do it statically.
* But we can figure out when there is a possibility wrt type signature we get.
*
* @since 2.18.3
Copy link
Member Author

Choose a reason for hiding this comment

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

Suggested change
* @since 2.18.3
* @since 2.19

cowtowncoder and others added 2 commits December 18, 2024 17:32
Co-authored-by: Kim, Joo Hyuk <beanskobe@gmail.com>
Comment on lines +51 to +54
// Unfortunately we can't check for EnumSet statically (if type indicated it,
// we'd have constructed `EnumSetSerializer` instead). But we can check that
// element type could possibly be an Enum.
_maybeEnumSet = elemType.isEnumType() || elemType.isJavaLangObject();
Copy link
Member Author

Choose a reason for hiding this comment

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

For 3.x version, would it be worth the effort trying to find other way instead of this?
And also parts with below code

// [databind#4849]/[databind#4214]: need to check for EnumSet
        final TypeSerializer typeSer = (_maybeEnumSet && value instanceof EnumSet<?>)
                ? null : _valueTypeSerializer;
                

Copy link
Member

Choose a reason for hiding this comment

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

If there is a way, sure, it would be great to get rid of this work-around.
But I am not sure how, considering the problem itself and how it occurs.
That is: I do not know how this could be avoided at all, regardless of compatibility concerns.

@cowtowncoder
Copy link
Member

Ok. So, fix is quite ugly, but I cannot think of a cleaner way to achieve this.
Basically we get "wrong" serializer (CollectionSerializer) in cases where nominal type is not EnumSet, and need to make CollectionSerializer aware of having to skip inclusion of type id for elements for case where collection happens to be EnumSet.

There was discrepancy b/w serialization (was not adding type id) vs deserialization (was expecting type id) in some cases. So, fix was also to remove earlier (#4214) changes that added type id handling for EnumSetDeserializer).

And why is type id not needed/wanted? Because for polymorphic typing we already have parent type id identified as something like java.util.EnumMap<EnumType>; anything else is redundant.

Will merge into 2.19 due to somewhat extensive change; basically changes serialization of EnumSet in some (hopefully rare) cases. So while new mechanism works better, there could be interoperability issues and there's no real way to avoid this.

@cowtowncoder cowtowncoder merged commit 959980e into FasterXML:2.19 Dec 19, 2024
8 checks passed
@JooHyukKim JooHyukKim deleted the fix-4849 branch December 19, 2024 01: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.

Not able to deserialize Enum with default typing after upgrading 2.15.4 -> 2.17.1
2 participants