[ 
https://issues.apache.org/jira/browse/FLINK-40218?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18125827#comment-18125827
 ] 

Sergey Nuyanzin commented on FLINK-40218:
-----------------------------------------

Merged as 
[fed133939df542016dbbb0e892a11eacbf9b93ae|https://github.com/apache/flink/commit/fed133939df542016dbbb0e892a11eacbf9b93ae]

> Let callers that already hold parsed JSON build a Variant without a String 
> round trip
> -------------------------------------------------------------------------------------
>
>                 Key: FLINK-40218
>                 URL: https://issues.apache.org/jira/browse/FLINK-40218
>             Project: Flink
>          Issue Type: Improvement
>          Components: API / Type Serialization System
>            Reporter: Ramin Gharib
>            Assignee: Ramin Gharib
>            Priority: Major
>              Labels: pull-request-available
>
> *Description*
> The only way to build a \{{Variant}} from JSON today is from a \{{String}}. 
> \{{PARSE_JSON}} and the internal 
> \{{BinaryVariantInternalBuilder.parseJson(String)}} both create a Jackson 
> parser over the text and walk its tokens in \{{buildJson}}.
> A caller that already holds parsed JSON cannot use that work. It must write 
> its data back to a \{{String}}, which flink-core then parses a second time:
> {code}
> bytes --(caller parses)--> tree --(toString)--> String --(flink-core parses 
> again)--> Variant
> {code}
> Two things keep callers on this path:
>  # *There is no entry point that takes a parser.* \{{parseJson(JsonParser, 
> boolean)}} exists but is private.
>  # *Jackson types do not cross shading boundaries.* The builder uses Flink's 
> shaded \{{org.apache.flink.shaded.jackson2...JsonParser}}. A caller with its 
> own, unshaded Jackson cannot pass in its parser or tree. A \{{String}} is the 
> only type both sides share.
> *Proposed change*
> Two entry points on the \{{@Internal}} \{{BinaryVariantInternalBuilder}}:
> ||The caller holds||Entry point||
> |Flink's shaded Jackson \{{JsonParser}}|\{{parseJson(JsonParser, boolean)}}, 
> now public|
> |JSON in another form, such as a tree from its own Jackson|walk it with the 
> existing \{{append*}}, \{{addKey}} and \{{finishWritingObject}} methods, and 
> call the new \{{appendJsonNumber(String)}} for numbers|
> {\{parseJson(JsonParser, boolean)}} expects the parser on the value's first 
> token and leaves it on the value's last token, so a format can read a VARIANT 
> field in the middle of a record.
> {\{appendJsonNumber(String)}} reads the literal with the same Jackson factory 
> and number code as \{{PARSE_JSON}}. A number is therefore stored byte for 
> byte like \{{PARSE_JSON}} stores it: the smallest integer, else a decimal, 
> else a finite double. Anything that is not exactly one JSON number fails.
> A walker over an unshaded Jackson tree then looks like this:
> {code:java}
> case NUMBER:
>     if (node.isIntegralNumber() && node.canConvertToLong()) {
>         builder.appendNumeric(node.longValue());
>     } else {
>         builder.appendJsonNumber(node.asText());
>     }
> {code}
> *Design notes*
>  * *Push instead of a token-source interface.* An earlier proposal added a 
> pull-based \{{VariantJsonSource}} interface that the builder reads from. It 
> is replaced by one push method. The other VARIANT producers push into the 
> builder too, such as \{{ToVariantConverter}} for \{{CAST(... AS VARIANT)}}. 
> One method is a smaller surface than an interface with an enum. 
> \{{PARSE_JSON}} keeps its own code path unchanged.
>  * *A String literal, not a \{{Number}}.* \{{PARSE_JSON}} picks the type from 
> how a number is written, for example an exponent means DOUBLE. A 
> \{{BigDecimal}} cannot tell \{{1e-7}} from \{{0.0000001}}, which 
> \{{PARSE_JSON}} stores as DOUBLE and DECIMAL. The text keeps that information.
>  * *No hand-written number grammar.* \{{appendJsonNumber}} lets Jackson 
> validate the literal, so it rejects \{{+5}}, \{{0x1p4}}, \{{1.5f}} and 
> \{{1,5}} exactly like \{{PARSE_JSON}} doe
> *Scope*
> Moving the \{{json}} format onto the new parser entry-XXXXX. That change is 
> not behavior-neutral: theformat rounds VARIANT floats through a \{{double}} 
> today, so for example \{{1e400}} becomes the string \{{"Infinity"}}. It needs 
> its
> own release note.
> *Compatibility*
> Additive and \{{@Internal}}. \{{PARSE_JSON}}, \{{TRY_PA} format do not 
> change. \{{addKey}} now looks a key up once instead of twice.
> *Verifying this change*
>  * \{{appendJsonNumber}} is byte-for-byte equal to {{tegers at every width, 
> values beyond a long,decimals, exponents and surrounding whitespace.
>  * It rejects non-JSON literals, other JSON values s trailing content such as 
> \{{5 6}}, and numbersoutside the double range.
>  * A parser read in the middle of a document is left.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to