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

Feature : Support naming strategy for enums #3792

Merged
merged 14 commits into from
Mar 15, 2023

Conversation

JooHyukKim
Copy link
Member

@JooHyukKim JooHyukKim commented Feb 22, 2023

Description

@JooHyukKim
Copy link
Member Author

Can I get some test case ideas on EnumNamingStrategies.CamelCaseStrategy? Currently the its implementation is exactly same as PropertyNamingStrategies.UpperSnakeCaseStrategy.translate()(🔗Link) and it does too much....

@JooHyukKim JooHyukKim changed the title Support naming strategy for enums Feature : Support naming strategy for enums Feb 23, 2023

public interface EnumNamingStrategy {

public String translate(String value);
Copy link
Member

Choose a reason for hiding this comment

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

Would be good to add Javadocs to explain direction, and name argument as something more specific than value.
I think that value would be Enum.name() to translate, and result is the "external" value used in JSON, right?

synchronized (this) {
namingStrategy = _namingStrategy;
if (namingStrategy == null) {
EnumNaming enumNamingAnnotation = _valueClass.getAnnotation(EnumNaming.class);
Copy link
Member

Choose a reason for hiding this comment

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

No; all access to annotations should go via AnnotationIntrospector, not check directly.

@cowtowncoder
Copy link
Member

Ok looks like a good starting point. Some suggestions:

  1. All annotation access needs to be done via AnnotationIntrospector (and JacksonAnnotationIntrospector implementation), not directly. (I think there may be one or two exceptions but no new ones should be added). This is partly so that mix-in annotations work
  2. All translations should be done when constructing EnumDeserializer and EnumSerializer -- not during reads/writes. Part of this has to do with performance, but it also keeps deserializer/serializer implementations simpler: they still just deal with a static list of values. This is how property naming strategies work too.

@JooHyukKim
Copy link
Member Author

Thanks you for the review! 🙏🏼
I will get back with your reviews applied

*
* @since 2.15
*/
public static class CamelCaseStrategy implements EnumNamingStrategy {
Copy link
Member Author

Choose a reason for hiding this comment

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

Implementation of convertEnumToExternalName here is from Guava's com.google.base.CaseFormat utility class.

@JooHyukKim JooHyukKim force-pushed the Naming-strategy-for-enums- branch 2 times, most recently from e1f405f to 3556f6e Compare March 5, 2023 06:25
@JooHyukKim JooHyukKim force-pushed the Naming-strategy-for-enums- branch from 3556f6e to c67804f Compare March 6, 2023 13:03
@@ -253,6 +272,8 @@ protected Object _fromString(JsonParser p, DeserializationContext ctxt,
{
CompactStringObjectMap lookup = ctxt.isEnabled(DeserializationFeature.READ_ENUMS_USING_TO_STRING)
? _getToStringLookup(ctxt) : _lookupByName;
lookup = _hasEnumNaming(ctxt) ? _getEnumNamingLookup(ctxt) : lookup;
Copy link
Member

Choose a reason for hiding this comment

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

Ok, getting better, but I think all of introspection really should be done when constructing EnumDeserializer, and not dynamically. That avoids having to use synchronization and we just replace names used when constructing/initializing deserializer.

synchronized (this) {
lookup = _lookupByEnumNaming;
if (lookup == null) {
EnumNamingStrategy namingStrategy = EnumPropertiesCollector
Copy link
Member

Choose a reason for hiding this comment

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

I think this should be fetched via AnnotationIntrospector, directly. Or, if we prefer, via DeserializationContext.

Copy link
Member Author

Choose a reason for hiding this comment

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

Agreed. Running introspection during construction like you suggested will doors to more information, so the helper class EnumPropertiesCollector will not be needed.

@cowtowncoder
Copy link
Member

Ok good, I can see this forming: functionality is there just need to (I think) rearrange things slightly -- mostly to handle all renaming, I think, when constructing EnumSerializer/EnumDeserializer. This allows keeping things immutable, reduce synchronized access and simplifies code.

I added some notes but probably not enough. I'll try to give some more feedback when I have time.

// 19-Oct-2016, tatu: Used to just return DEFAULT_KEY_SERIALIZER but why not:
return new Default(Default.TYPE_TO_STRING, rawKeyType);
}

Copy link
Member Author

@JooHyukKim JooHyukKim Mar 11, 2023

Choose a reason for hiding this comment

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

Right above this method, there is exact same method without EnumSerializer.constructEnumNamingStrategyValues(config, (Class<Enum<?>>) rawKeyType, annotatedClass)).

Copy link
Member

Choose a reason for hiding this comment

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

I think method above should be marked as @deprecated unless it is actually called from somewhere?

Copy link
Member Author

Choose a reason for hiding this comment

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

True. Added @deprecated annotation and documented it

@JooHyukKim
Copy link
Member Author

JooHyukKim commented Mar 11, 2023

Suggested changes based on the feedback provided by @cowtowncoder seem have been implemented. Changes made include:

  1. Targeting the EnumDeserializer, StdKeyDeserializer, EnumSerializer, StdKeySerializer classes.
  2. Arranging all introspection of the @EnumNaming annotation to be done during construction phase.
  3. Making use of the AnnotationIntrospector for introspection wherever possible, while encapsulating the implementation contained in methods that create EnumValues and EnumResolver.

@JooHyukKim JooHyukKim requested a review from cowtowncoder March 11, 2023 23:11
@cowtowncoder
Copy link
Member

Ok this looks pretty good. I wish there was a way to combine 2 instances of CompactStringObjectMap (and matching thing for serializers), but that is probably not possible due to dynamic nature of DeserializationFeature.READ_ENUMS_USING_TO_STRING.

I think I'll want to go over the code one more time but maybe get it merged tomorrow.

Thank you very much @JooHyukKim for all the improvements here... this should be a nice new feature once we get it merged in for 2.15.0.

@JooHyukKim
Copy link
Member Author

I think I'll want to go over the code one more time but maybe get it merged tomorrow.

Thank you for for yall's reviews also ✌️
Okay, I will pause searching for improvements now and wait for your review @cowtowncoder.

*
* @since 2.15
*/
public class EnumPropertiesCollector {
Copy link
Member

Choose a reason for hiding this comment

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

Let's rename as... maybe EnumNamingStrategyFactory?

Copy link
Member Author

Choose a reason for hiding this comment

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

True, I was expecting this class would be come Enum version of Pojo's POJOPropertiesCollector. But I guess time will tell. I changed the name.

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 had expected that this class would become the Enum version of POJOPropertiesCollector for Pojos, but it is not yet clear and you are right. I renamed the class accordingly. 🙏🏼

@JooHyukKim JooHyukKim requested a review from cowtowncoder March 14, 2023 22:37
@cowtowncoder cowtowncoder merged commit 5343866 into FasterXML:2.15 Mar 15, 2023
@cowtowncoder
Copy link
Member

Whoa. This was gnarly to merge into main/3.0. :)
(but it's done now)

@JooHyukKim
Copy link
Member Author

Whoa. This was gnarly to merge into main/3.0. :)
(but it's done now)

Niceee

@JooHyukKim JooHyukKim deleted the Naming-strategy-for-enums- branch May 22, 2023 13:58
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.

3 participants