Add FunctionalScalarDeserializer for functional-style deserialization#5595
Conversation
…FasterXML#4004) Add functional-style deserializer extending StdScalarDeserializer that allows using Function<String, T> or BiFunction<JsonParser, DeserializationContext, T> for simple scalar-to-object conversions.
| * Usage examples: | ||
| * <pre> | ||
| * // Simple case - method reference | ||
| * new FunctionalScalarDeserializer<>(Bar.class, Bar::of) |
There was a problem hiding this comment.
Let's fix the brackets, and ones below.
| * new FunctionalScalarDeserializer<>(Bar.class, Bar::of) | |
| * new FunctionalScalarDeserializer<>(Bar.class, Bar::of) |
| /** | ||
| * Tests for {@link FunctionalScalarDeserializer}. | ||
| */ | ||
| // [databind#4004] |
There was a problem hiding this comment.
Let's add more meaningful information, see this test class
| * Tests for {@link FunctionalScalarDeserializer}. | ||
| */ | ||
| // [databind#4004] | ||
| public class FunctionalScalarDeserializerTest |
There was a problem hiding this comment.
| public class FunctionalScalarDeserializerTest | |
| public class FunctionalScalarDeserializer4004Test |
| Bar result = mapper.readValue("\"\"", Bar.class); | ||
| assertNull(result); | ||
| } | ||
| } |
| * Subclasses may override to provide custom behavior. | ||
| * Default implementation returns null. | ||
| */ | ||
| protected Object _deserializeFromEmptyStringDefault(DeserializationContext ctxt) |
There was a problem hiding this comment.
Does this need to be protected why not private?
There was a problem hiding this comment.
Good point. I've reconsidered the design.
The core intent of FunctionalScalarDeserializer is to accept a function to deserialize into a user-specified type. Users are expected to customize behavior by passing a Function or BiFunction, rather than by subclassing.
Given this, I believe we should start with the simplest form. If subclassing becomes necessary in the future, we can easily expand visibility from private to protected without breaking backward compatibility.
I'll apply the following changes:
_deserializeFromEmptyStringDefault: change to private_deserializeFromEmptyString: change to private- Remove the copy constructor (as it is currently unused)
| @Test | ||
| public void testSimpleFunctionFromString() throws Exception | ||
| { | ||
| SimpleModule module = new SimpleModule("test", Version.unknownVersion()); |
There was a problem hiding this comment.
Since version value is fixed toVersion.unknownVersion() in all places, let's replace ALL SimpleModule declarations with
| SimpleModule module = new SimpleModule("test", Version.unknownVersion()); | |
| SimpleModule module = new SimpleModule("test"); |
src/main/java/tools/jackson/databind/deser/std/FunctionalScalarDeserializer.java
Show resolved
Hide resolved
Also @jhan0121 could this PR result in non-negative test coverage change? :-) tnx |
|
Thanks for the detailed review, @JooHyukKim! I have addressed your comments and updated the code accordingly. |
| } | ||
|
|
||
| try { | ||
| return _function.apply(p, ctxt); |
There was a problem hiding this comment.
Ok this is problematic: this ignores text altogether; and will fail for
text = ctxt.extractScalarFromObject(p, this, _valueClass);
case from above. I think it will be necessary to keep track of type of original Function being passed and:
- In case of "complex" 2-arg function, just invoke that function without doing about any of things in this method
- In case of "simple" from-string function, use code here and just pass
textto function
There was a problem hiding this comment.
Thanks for catching this! You're right, the extracted text was being ignored.
I've fixed it by separating the storage into two distinct fields to handle each case correctly:
_biFunction: invoked directly without preprocessing._stringFunction: receives the extracted text directly.
src/main/java/tools/jackson/databind/deser/std/FunctionalScalarDeserializer.java
Outdated
Show resolved
Hide resolved
src/main/java/tools/jackson/databind/deser/std/FunctionalScalarDeserializer.java
Show resolved
Hide resolved
cowtowncoder
left a comment
There was a problem hiding this comment.
Looks good, almost ready to merge. Couple of minor comments added.
FunctionalScalarDeserializer for functional-style deserialization
…ckson-databind into 4004-functional-deserializer
Implements: #4004
This PR add functional-style deserializer extending StdScalarDeserializer that allows using Function<String, T> or BiFunction<JsonParser, DeserializationContext, T> for simple scalar-to-object conversions.