-
Notifications
You must be signed in to change notification settings - Fork 117
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
Add 1-based Month[De]serializer
enabled with JavaTimeFeature.ONE_BASED_MONTHS
option
#292
Add 1-based Month[De]serializer
enabled with JavaTimeFeature.ONE_BASED_MONTHS
option
#292
Conversation
datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/JSR310Module.java
Outdated
Show resolved
Hide resolved
datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/JavaTimeFeature.java
Show resolved
Hide resolved
datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/JavaTimeModule.java
Outdated
Show resolved
Hide resolved
datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/MonthDeserializer.java
Outdated
Show resolved
Hide resolved
datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/MonthDeserializer.java
Outdated
Show resolved
Hide resolved
datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/MonthDeserializer.java
Outdated
Show resolved
Hide resolved
datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/MonthDeserializer.java
Outdated
Show resolved
Hide resolved
datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/MonthDeserializer.java
Outdated
Show resolved
Hide resolved
if (_oneBaseMonths) { | ||
return Month.of(monthNo); | ||
} | ||
return Month.values()[monthNo]; |
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.
Same as above, but more important as we don't want to get ArrayIndexOutOfBundsException
...
datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/MonthDeserializer.java
Outdated
Show resolved
Hide resolved
datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/MonthDeserTest.java
Outdated
Show resolved
Hide resolved
datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/MonthDeserTest.java
Outdated
Show resolved
Hide resolved
@etrandafir93 First of all, thank you for this contribution! I added a few suggestions, mostly to change things that could be done in better way. One practical thing before merging (once we get code all cleaned up!) is CLA: unless we have received one before, we'd need it from here: https://github.com/FasterXML/jackson/blob/master/contributor-agreement.pdf and the usual way is to print, fill & sign, scan/photo, email to Thank you once again; looking forward to merging this useful new feature! |
@etrandafir93 I figured it might be quicker for me to make suggested changes instead of explaining what and how should be changed. But one thing that is bit worse off now, and that needs to be figure out is this: should "Stringified" numbers be accepted like regular JSON numbers or not? Other deserializers only allow them for special case of backends that have I did not add bounds checks for numbers; those should be done etc. |
@cowtowncoder - sure, feel free to commit on by branch. It's the first time I'm looking into the code and I'm not very familiar with it, but here's another idea that will allow us to skip re-implementing this parsing: If the feature is OFF (default) we can delegate to the generic enum deserializer, making sure we are 100% backaward compatible. Basically, a very simple decorator that wraps the generic enum deserializer. What do you think? |
@etrandafir93 Ah! Conceptually I like the idea a lot -- and it should be quite compatible with existing handling, too (since The challenge, then, becomes that of implementing delegating deserializer. A good starting point would be And then Above may not sound particularly simple, but that is the correct way to do it and should work very well. I can help with complications, if any. |
hello @cowtowncoder, I have made some changes to start using BeanDeserializerModifier and I believe i'm on the right track. However, I'm not sure I've fully understood your instructions. Can you take a look at the latest commit? Is there a way of registering the BeanDeserializerModifier for a specific type better than what I did with the if Thanks for the support and quick replies! |
...src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/MonthEnumDeserializerModifier.java
Outdated
Show resolved
Hide resolved
...src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/MonthEnumDeserializerModifier.java
Outdated
Show resolved
Hide resolved
...src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/MonthEnumDeserializerModifier.java
Outdated
Show resolved
Hide resolved
...src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/MonthEnumDeserializerModifier.java
Outdated
Show resolved
Hide resolved
if(type.getRawClass() != Month.class) { | ||
return deserializer; | ||
} | ||
return new JsonDeserializer<Enum>() { |
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.
Ok, this is too simplistic: my idea was to extend DelegatingDeserializer
passing the default deserializer and overriding its deserialize()
method -- ONLY handling special case of 1-based month and number, otherwise calling super.deserialize()
(getDelegatee().deserialize(...)
.
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.
I have applied your suggestions and a few other small changes. Can you take a look when you'll have some time?
Also, I haven't tackled the part about serialization yet - will we follow the same approach?
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.
Looks pretty good so far: added couple of suggestions again, nothing major.
As to serializer, yeah, I think same pattern is usable: BeanSerializerModifier
to wrap JsonSerializer
.
Although may need to look at logic of EnumSerializer
for clues on how handling works wrt configuration (see EnumSerializer.serialize(...)
) -- I think override is only needed for case where we serialize using index; as text should be fine.
import com.fasterxml.jackson.databind.JsonDeserializer; | ||
import com.fasterxml.jackson.databind.deser.std.DelegatingDeserializer; | ||
import com.fasterxml.jackson.databind.exc.InvalidFormatException; | ||
|
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.
Add @since 2.17
in Javadoc here too
} | ||
|
||
private boolean _isNumberAsString(String text, JsonToken token) throws IOException { | ||
String regex = "[\"']?\\d{1,2}[\"']?"; |
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.
Ok, couple of things: parser.getText()
will return contents, so no quotes around it, can leave those out.
And make sure to create pre-compiled Pattern
as static member of class: otherwise RegEx state machine is re-create for every call... and that's pretty expensive (and more importantly easily avoidable :) ).
/* | ||
&& we write the enum ordinal (int) value, | ||
via WRITE_ENUMS_USING_INDEX or other similar construct | ||
*/ |
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.
@cowtowncoder - Hello again and sorry for the late reply, I finally got some time to continue working here.
I have applied your suggestions and refactored the code a bit.
Regarding serialization, I am not sure how to check if we ar serializing the enum as an integer (via WRITE_ENUMS_USING_INDEX
) or other similar configuration. How should I do it?
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.
Hmmh. Good question. Ideally we should be able to use EnumSerializer
but that seems difficult if not impossible, at least by sub-classing (method serialize()
is final for one but also initialization is quite tricky).
Similarly delegation is difficult to use wrt changing of value to serialize.
But EnumSerializer
has useful pieces at least.
"createContextual":
"serialize()" :
and "_isShapeWrittenUsingIndex"
implement logic.
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.
And thinking out aloud further it'd be nice to use delegating serializer. There is StdDelegatingSerializer
(but no intermediate DelegatingSerializer
can't remember why not) which may or may not.
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.
@cowtowncoder - I have tried a few things but couldn't find the best way of doing it using these methods.
However, I managed to pass the WRITE_ENUMS_USING_INDEX feature as a Supplier that can be later checked , during the serialization - can you take a look? si there a more straight-forward way of doing this?
@Override | ||
public JsonDeserializer<?> modifyEnumDeserializer(DeserializationConfig config, JavaType type, BeanDescription beanDesc, JsonDeserializer<?> defaultDeserializer) { | ||
if (type.hasRawClass(Month.class)) { | ||
return new MonthDeserializer((JsonDeserializer<Enum>) defaultDeserializer, _oneBaseMonths); |
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.
Shouldn't this only need to be returned if _oneBasedMonths
is true? That might simplify handling a bit when there are fewer checks.
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.
@cowtowncoder - it's mostly about the naming and meaning of the classes. If we do it like this, perhaps it's better to rename the deserializer from MonthDeserializer
to OneBasedMonthDeserializer
and make it always updated the value returned by the delegate (without checking the _oneBasedMonths
flag -- and move the check here).
What do you think?
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.
Yes, I think that makes sense -- I like explicit naming.
@Override | ||
public JsonSerializer<?> modifyEnumSerializer(SerializationConfig config, JavaType valueType, BeanDescription beanDesc, JsonSerializer<?> serializer) { | ||
if (valueType.hasRawClass(Month.class)) { | ||
return new MonthSerializer((JsonSerializer<Enum>) serializer, _oneBaseMonths); |
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.
Similar to deserializer: shouldn't this only need to be returned if _oneBasedMonths
is true?
That might simplify handling a bit when there are fewer checks.
private final boolean _oneBaseMonths; | ||
|
||
public JavaTimeSerializerModifier() { | ||
this(false); |
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.
Is this constructor needed?
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.
no, I removed it now 👍
public class JavaTimeDeserializerModifier extends BeanDeserializerModifier { | ||
private final boolean _oneBaseMonths; | ||
|
||
public JavaTimeDeserializerModifier() { |
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.
Probably not needed?
datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/JavaTimeModule.java
Outdated
Show resolved
Hide resolved
|
||
@Override | ||
public void serialize(Enum<Month> value, JsonGenerator gen, SerializerProvider serializers) throws IOException { | ||
if (_serializeEnumsByIndex.get()) { |
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.
Use SerializerProvider.isEnabled(SerializationFeature.WRITE_ENUMS_USING_INDEX)
instead of passing Supplier
.
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.
Actually if/when serializer only registered when feature is enabled, can drop the check altogether.
At this point, I'd need CLA before proceeding further. |
CLA received, not blocking any more. |
private final boolean _oneBaseMonths; | ||
private final Supplier<Boolean> _serializeEnumsByIndex; | ||
|
||
public JavaTimeSerializerModifier(boolean oneBaseMonths, Supplier<Boolean> serializeEnumsByIndex) { |
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.
As per other discussions, can drop Supplier
and checks altogher as Serializer is only used if one-based-months feature is set.
With CLA received, looks like there are only small changes needed:
and then I can merge this into 2.17 branch. Thanks! |
@etrandafir93 Ok: I fixed the one failing test (it was assuming coercion from Empty String is allowed by default; it is not for |
@etrandafir93 Ok, made all changes I wanted and ready to merge. But wanted to give a chance to see if there's anything you would want to change still. Please LMK and I'll merge this when ready! |
@cowtowncoder - nothing else to add from my side. |
Month[De]serializer
and JavaTimeFeature
option
Month[De]serializer
and JavaTimeFeature
optionMonth[De]serializer
enabled with JavaTimeFeature.ONE_BASED_MONTHS
option
Implements #274: