Skip to content

Conversation

@JooHyukKim
Copy link
Member

@JooHyukKim JooHyukKim commented Apr 29, 2023

relates to #90. "Miminal" implementation of Cache serialization.

continue;
}
gen.writeFieldName(key.toString());
provider.defaultSerializeValue(value, gen);
Copy link
Member

Choose a reason for hiding this comment

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

This won't support polymorphism and is not as efficient as if serializer was fetched eagerly (like regular Maps will do, if possible; or if not possible, retain (possibly generic) element JavaType) -- but for a minimal implementation it's a clear improvement so that's fine.

@cowtowncoder
Copy link
Member

Looks good so far. You may want to look at standard MapSerializer to see how to maybe try to add full typed handling (or even partial). That requires constructing instances with resolved JavaType to know actual declared types of Key and Value types, instead of assuming Object. Doing so is required at least for polymorphic types (wrt values), but also to support some key types like java.util.Date where Object.toString() is not what regular Map serializer would use.

I think what I would want to see is at least extracting and passing JavaType.

Now that wrote above, though, I realize that this is not as trivial as thought because Cache is not Map and as such does not automatically extract generic type information.

But! Have a look at GuavaTypeModifier and see how it "upgrade" Multimap into "map-like" type: I think same should be done for Cache. And see how Multimap's generic type information is then available and used in GuavaSerializers method findMapLikeSerializer().
This is the good way to get type information.

I am ok with not necessarily implementing everything this allows, but at least get type information so handling may be improved.

LMK if you need help here, type refinements are pretty advanced functionality.

@JooHyukKim
Copy link
Member Author

Looks good so far. You may....

Thank you for your detailed feedback on the PR 🙏🏼 I will work on it one by one and get back soon as I can~

Set<String> ignored = (ignorals == null) ? null : ignorals.getIgnored();
return new CacheSerializer(type, beanDesc,
keySerializer, elementTypeSerializer, elementValueSerializer, ignored, filterId);
}
Copy link
Member Author

Choose a reason for hiding this comment

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

Identical to that of MultimapSerializer right above.

import java.util.ArrayList;
import java.util.List;

public class CacheSerializationTest extends ModuleTestBase {
Copy link
Member Author

@JooHyukKim JooHyukKim May 1, 2023

Choose a reason for hiding this comment

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

I have collected and converted most of the tests related to MultiMap for Cache. After implementing the deserialization part, we can further expand the range of tests. For now, we have covered the basic functionality, including:

  • Polymorphic type handling
  • JsonInclude behavior
  • Key ordering

Please let me know if there are any additional test cases that should be included! 🙏🏼🙏🏼

*/
public class CacheSerializer
extends ContainerSerializer<Cache<?, ?>>
implements ContextualSerializer
Copy link
Member Author

@JooHyukKim JooHyukKim May 1, 2023

Choose a reason for hiding this comment

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

Since we get Map<?, ?> as the snapshot value of current Cache. I thought it would make sense to use the majority of "battle-hardend" implementations from MultimapSerializer class.

I will write notes on which part here in CacheSerializer is different from MultimapSerializer.

Copy link
Member

Choose a reason for hiding this comment

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

That sounds like a good idea to me.

*/

@Override
public JsonSerializer<?> createContextual(SerializerProvider provider, BeanProperty property) throws JsonMappingException {
Copy link
Member Author

@JooHyukKim JooHyukKim May 1, 2023

Choose a reason for hiding this comment

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

This whole method is identical to

public JsonSerializer<?> createContextual(SerializerProvider provider,

Comment on lines +328 to +349
// Second, serialize value
Object vv = entry.getValue();
// is this even possible?
if (vv == null) {
provider.defaultSerializeNull(gen);
continue;
}
// serialize value
JsonSerializer<Object> valueSer = _valueSerializer;
if (valueSer == null) {
Class<?> cc = vv.getClass();
valueSer = serializers.serializerFor(cc);
if (valueSer == null) {
valueSer = _findAndAddDynamic(serializers, cc, provider);
serializers = _dynamicValueSerializers;
}
}
if (_valueTypeSerializer == null) {
valueSer.serialize(vv, gen, provider);
} else {
valueSer.serializeWithType(vv, gen, provider, _valueTypeSerializer);
}
Copy link
Member Author

@JooHyukKim JooHyukKim May 1, 2023

Choose a reason for hiding this comment

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

There is no for-loop here unlike Multimap where value is a List ...

if ((ignored != null) && ignored.contains(key)) {
continue;
}
Object value = entry.getValue();
Copy link
Member Author

Choose a reason for hiding this comment

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

This serializeFilteredFields(Map<?, ?>, JsonGenerator, SerializerProvider)method is almost identical to that of MultimapSerializer except current line --no collection, just plain object.

*/

@Override
public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint)
Copy link
Member Author

@JooHyukKim JooHyukKim May 1, 2023

Choose a reason for hiding this comment

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

This method is identical to that of MultimapSerializer

_dynamicValueSerializers = result.map;
}
return result.serializer;
}
Copy link
Member Author

Choose a reason for hiding this comment

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

This method is identical to that of MultimapSerializer

_dynamicValueSerializers = result.map;
}
return result.serializer;
}
Copy link
Member Author

Choose a reason for hiding this comment

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

This method is identical to that of MultimapSerializer

Copy link
Member

Choose a reason for hiding this comment

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

Also used by many databind-provided serializers.

provider.reportMappingProblem("Failed to sort Multimap entries due to `NullPointerException`: `null` key?");
return null;
}
}
Copy link
Member Author

@JooHyukKim JooHyukKim May 1, 2023

Choose a reason for hiding this comment

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

Since we are dealing with the standard JDK Map type (unlike Multimap), it seems appropriate to implement full ordering as in MapSerializer._orderEntries.

However, the fact that "Cache itself does not support null keys" makes me think that using MapSerializer might be an overkill from others' perspectives. Therefore, I figured like to hear others' opinions before proceeding 🥹

Copy link
Member

@cowtowncoder cowtowncoder May 1, 2023

Choose a reason for hiding this comment

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

Yeah no need to support nulls (i.e. can operate without concern there).
Guava is notoriously null-antagonistic library :)

@cowtowncoder
Copy link
Member

Looks good @JooHyukKim. Is this ready to be merged from your end? (just want to make sure I won't merge too early).

Copy link
Member

@cowtowncoder cowtowncoder left a comment

Choose a reason for hiding this comment

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

LGTM

@JooHyukKim
Copy link
Member Author

Looks good @JooHyukKim. Is this ready to be merged from your end? (just want to make sure I won't merge too early).

Yes, it is ~ 🙆🏽‍♂️🙆🏽‍♂️

@cowtowncoder cowtowncoder merged commit a9e2a2e into FasterXML:2.16 May 1, 2023
@cowtowncoder cowtowncoder modified the milestone: 2.6. May 1, 2023
@JooHyukKim
Copy link
Member Author

@cowtowncoder Thank your details reviews as always 👍🏼👍🏼

One question tho, is it reasonable to move on to implementing CacheDeserializer? Or you might have some plan to write some set up code like you did with serializer.

@cowtowncoder
Copy link
Member

@JooHyukKim I'd guess users would want a deserializer too, yes, so +1 for that. I don't think "empty" implementation would be useful here.

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