Advertisement
Guest User

Untitled

a guest
Apr 4th, 2020
331
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 5 27.98 KB | None | 0 0
  1.  
  2. <!DOCTYPE html>
  3. <html lang="en">
  4. <head>
  5.     <meta charset="UTF-8">
  6.     <title>HLDiff</title>
  7.     <style type="text/css">
  8.         :root {
  9.             --add-color: rgba(124, 252, 0, 0.5);
  10.             --move-color: rgba(100, 149, 237, 0.5);
  11.             --update-color: rgba(244, 164, 96, 0.5);
  12.             --delete-color: rgba(255, 0, 0, 0.5);
  13.             --line-color: rgb(0, 0, 0);
  14.         }
  15.  
  16.         .wrapper {
  17.             display: grid;
  18.             grid-template-columns: 40% 20% 40%;
  19.         }
  20.  
  21.         .code {
  22.             border: 1px solid black;
  23.         }
  24.  
  25.         figure {
  26.             margin-inline-start: 5pt;
  27.             margin-inline-end: 5pt;
  28.         }
  29.  
  30.         code {
  31.             display: block;
  32.             white-space: pre-wrap;
  33.             word-break: break-all;
  34.         }
  35.  
  36.         .added {
  37.             background-color: var(--add-color);
  38.         }
  39.  
  40.         .removed {
  41.             background-color: red;
  42.         }
  43.  
  44.         .moved {
  45.             background-color: var(--move-color);
  46.         }
  47.  
  48.         .updated {
  49.             background-color: var(--update-color);
  50.         }
  51.  
  52.         .diff {
  53.             position: relative;
  54.         }
  55.  
  56.         .change {
  57.             position: absolute;
  58.             width: calc(100% - 20pt);
  59.             padding: 10pt;
  60.             display: block;
  61.         }
  62.  
  63.         .change-addition {
  64.             border: 2px solid var(--add-color);
  65.             background-color: #7CFC0033;
  66.         }
  67.  
  68.         .change-addition:hover {
  69.             background-color: #7CFC00AA;
  70.         }
  71.  
  72.         .change-move {
  73.             border: 2px solid var(--move-color);
  74.             background-color: #6495ED33;
  75.         }
  76.  
  77.         .change-move:hover {
  78.             background-color: #6495EDAA;
  79.         }
  80.  
  81.         .change-update {
  82.             border: 2px solid var(--update-color);
  83.             background-color: #F4A46033;
  84.         }
  85.  
  86.         .change-update:hover {
  87.             background-color: #F4A460AA;
  88.         }
  89.  
  90.         .change-delete {
  91.             border: 2px solid var(--delete-color);
  92.             background-color: #FF000033;
  93.         }
  94.  
  95.         .change-delete:hover {
  96.             background-color: #FF0000AA;
  97.         }
  98.  
  99.         .svg {
  100.             position: absolute;
  101.             top: 0;
  102.             left: 0;
  103.             width: 100%;
  104.             height: 100000pt;
  105.         }
  106.  
  107.         .line {
  108.             z-index: 100;
  109.             stroke-width: 3px;
  110.             stroke: var(--line-color);
  111.         }
  112.  
  113.         svg {
  114.             pointer-events: none;
  115.         }
  116.  
  117.         svg * {
  118.             pointer-events: all;
  119.         }
  120.     </style>
  121. </head>
  122. <body>
  123.  
  124. <h1>Diff of 2 files</h1>
  125.  
  126.  
  127. <svg id="svg" class="svg" xmlns="http://www.w3.org/2000/svg">
  128.     <line id="line" class="line"></line>
  129. </svg>
  130.  
  131. <svg id="svg2" class="svg" xmlns="http://www.w3.org/2000/svg">
  132.     <line id="line2" class="line"></line>
  133. </svg>
  134.  
  135.  
  136. <div class="wrapper">
  137.     <figure class="code">
  138.         <figcaption>Before:</figcaption>
  139.  
  140.     <code>
  141. /*
  142.  * Copyright 2002-2019 the original author or authors.
  143.  *
  144.  * Licensed under the Apache License, Version 2.0 (the "License");
  145.  * you may not use this file except in compliance with the License.
  146.  * You may obtain a copy of the License at
  147.  *
  148.  *      https://www.apache.org/licenses/LICENSE-2.0
  149.  *
  150.  * Unless required by applicable law or agreed to in writing, software
  151.  * distributed under the License is distributed on an "AS IS" BASIS,
  152.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  153.  * See the License for the specific language governing permissions and
  154.  * limitations under the License.
  155.  */
  156.  
  157. package org.springframework.http.codec.json;
  158.  
  159. import java.io.IOException;
  160. import java.util.ArrayList;
  161. import java.util.List;
  162. import java.util.function.Function;
  163.  
  164. import com.fasterxml.jackson.core.JsonFactory;
  165. import com.fasterxml.jackson.core.JsonParser;
  166. import com.fasterxml.jackson.core.JsonProcessingException;
  167. import com.fasterxml.jackson.core.JsonToken;
  168. import com.fasterxml.jackson.core.async.ByteArrayFeeder;
  169. import com.fasterxml.jackson.databind.DeserializationContext;
  170. import com.fasterxml.jackson.databind.ObjectMapper;
  171. import com.fasterxml.jackson.databind.deser.DefaultDeserializationContext;
  172. import com.fasterxml.jackson.databind.util.TokenBuffer;
  173. import reactor.core.Exceptions;
  174. import reactor.core.publisher.Flux;
  175.  
  176. import org.springframework.core.codec.DecodingException;
  177. import org.springframework.core.io.buffer.DataBuffer;
  178. import org.springframework.core.io.buffer.DataBufferLimitException;
  179. import org.springframework.core.io.buffer.DataBufferUtils;
  180.  
  181. /**
  182.  * {@link Function} to transform a JSON stream of arbitrary size, byte array
  183.  * chunks into a {@code Flux<TokenBuffer>} where each token buffer is a
  184.  * well-formed JSON object.
  185.  *
  186.  * @author Arjen Poutsma
  187.  * @author Rossen Stoyanchev
  188.  * @author Juergen Hoeller
  189.  * @since 5.0
  190.  */
  191. final class Jackson2Tokenizer {
  192.  
  193.     private final JsonParser parser;
  194.  
  195.     private final DeserializationContext deserializationContext;
  196.  
  197.     private final boolean tokenizeArrayElements;
  198.  
  199.     <span class="changed-code moved code-change-0">private TokenBuffer tokenBuffer;</span>
  200.  
  201.     private int objectDepth;
  202.  
  203.     private int arrayDepth;
  204.  
  205.     <span class="changed-code moved code-change-1">private final int maxInMemorySize;</span>
  206.  
  207.     private int byteCount;
  208.  
  209.  
  210.     // TODO: change to ByteBufferFeeder when supported by Jackson
  211.     // See https://github.com/FasterXML/jackson-core/issues/478
  212.     private final ByteArrayFeeder inputFeeder;
  213.  
  214.  
  215.     private Jackson2Tokenizer(JsonParser parser, DeserializationContext deserializationContext,
  216.             boolean tokenizeArrayElements, int maxInMemorySize) {
  217.  
  218.         this.parser = parser;
  219.         this.deserializationContext = deserializationContext;
  220.         this.tokenizeArrayElements = tokenizeArrayElements;
  221.         <span class="changed-code moved code-change-3"><span class="changed-code updated code-change-19">this.tokenBuffer</span> = <span class="changed-code removed code-change-15">new TokenBuffer(parser, deserializationContext)</span></span>;
  222.         this.inputFeeder = (ByteArrayFeeder) this.parser.getNonBlockingInputFeeder();
  223.         this.maxInMemorySize = maxInMemorySize;
  224.     }
  225.  
  226.  
  227.     private List<TokenBuffer> tokenize(DataBuffer dataBuffer) {
  228.         int bufferSize = dataBuffer.readableByteCount();
  229.         byte[] bytes = new byte[bufferSize];
  230.         dataBuffer.read(bytes);
  231.         DataBufferUtils.release(dataBuffer);
  232.  
  233.         try {
  234.             this.inputFeeder.feedInput(bytes, 0, bytes.length);
  235.             List<TokenBuffer> result = parseTokenBufferFlux();
  236.             assertInMemorySize(bufferSize, result);
  237.             return result;
  238.         }
  239.         catch (JsonProcessingException ex) {
  240.             throw new DecodingException("JSON decoding error: " + ex.getOriginalMessage(), ex);
  241.         }
  242.         catch (IOException ex) {
  243.             throw Exceptions.propagate(ex);
  244.         }
  245.     }
  246.  
  247.     private Flux<TokenBuffer> endOfInput() {
  248.         return Flux.defer(() -> {
  249.             this.inputFeeder.endOfInput();
  250.             try {
  251.                 return Flux.fromIterable(parseTokenBufferFlux());
  252.             }
  253.             catch (JsonProcessingException ex) {
  254.                 throw new DecodingException("JSON decoding error: " + ex.getOriginalMessage(), ex);
  255.             }
  256.             catch (IOException ex) {
  257.                 throw Exceptions.propagate(ex);
  258.             }
  259.         });
  260.     }
  261.  
  262.     private List<TokenBuffer> parseTokenBufferFlux() throws IOException {
  263.         List<TokenBuffer> result = new ArrayList<>();
  264.  
  265.         // SPR-16151: Smile data format uses null to separate documents
  266.         boolean previousNull = false;
  267.         while (!this.parser.isClosed()) {
  268.             JsonToken token = this.parser.nextToken();
  269.             if (token == JsonToken.NOT_AVAILABLE ||
  270.                     token == null && previousNull) {
  271.                 break;
  272.             }
  273.             else if (token == null ) { // !previousNull
  274.                 previousNull = true;
  275.                 continue;
  276.             }
  277.             updateDepth(token);
  278.             if (!this.tokenizeArrayElements) {
  279.                 processTokenNormal(token, result);
  280.             }
  281.             else {
  282.                 processTokenArray(token, result);
  283.             }
  284.         }
  285.         return result;
  286.     }
  287.  
  288.     private void updateDepth(JsonToken token) {
  289.         switch (token) {
  290.             case START_OBJECT:
  291.                 this.objectDepth++;
  292.                 break;
  293.             case END_OBJECT:
  294.                 this.objectDepth--;
  295.                 break;
  296.             case START_ARRAY:
  297.                 this.arrayDepth++;
  298.                 break;
  299.             case END_ARRAY:
  300.                 this.arrayDepth--;
  301.                 break;
  302.         }
  303.     }
  304.  
  305.     private void processTokenNormal(JsonToken token, List<TokenBuffer> result) throws IOException {
  306.         this.tokenBuffer.copyCurrentEvent(this.parser);
  307.  
  308.         if ((token.isStructEnd() || token.isScalarValue()) && this.objectDepth == 0 && this.arrayDepth == 0) {
  309.             result.add(this.tokenBuffer);
  310.             <span class="changed-code removed code-change-17">this.tokenBuffer = new TokenBuffer(this.parser, this.deserializationContext)</span>;
  311.         }
  312.  
  313.     }
  314.  
  315.     private void processTokenArray(JsonToken token, List<TokenBuffer> result) throws IOException {
  316.         if (!isTopLevelArrayToken(token)) {
  317.             this.tokenBuffer.copyCurrentEvent(this.parser);
  318.         }
  319.  
  320.         if (this.objectDepth == 0 && (this.arrayDepth == 0 || this.arrayDepth == 1) &&
  321.                 (token == JsonToken.END_OBJECT || token.isScalarValue())) {
  322.             result.add(this.tokenBuffer);
  323.             <span class="changed-code moved code-change-2">this.tokenBuffer = new TokenBuffer(this.parser, this.deserializationContext);</span>
  324.         }
  325.     }
  326.  
  327.     private boolean isTopLevelArrayToken(JsonToken token) {
  328.         return this.objectDepth == 0 && ((token == JsonToken.START_ARRAY && this.arrayDepth == 1) ||
  329.                 (token == JsonToken.END_ARRAY && this.arrayDepth == 0));
  330.     }
  331.  
  332.     private void assertInMemorySize(int currentBufferSize, List<TokenBuffer> result) {
  333.         if (this.maxInMemorySize >= 0) {
  334.             if (!result.isEmpty()) {
  335.                 this.byteCount = 0;
  336.             }
  337.             else if (currentBufferSize > Integer.MAX_VALUE - this.byteCount) {
  338.                 raiseLimitException();
  339.             }
  340.             else {
  341.                 this.byteCount += currentBufferSize;
  342.                 if (this.byteCount > this.maxInMemorySize) {
  343.                     raiseLimitException();
  344.                 }
  345.             }
  346.         }
  347.     }
  348.  
  349.     private void raiseLimitException() {
  350.         throw new DataBufferLimitException(
  351.                 "Exceeded limit on max bytes per JSON object: " + this.maxInMemorySize);
  352.     }
  353.  
  354.  
  355.     /**
  356.      * Tokenize the given {@code Flux<DataBuffer>} into {@code Flux<TokenBuffer>}.
  357.      * @param dataBuffers the source data buffers
  358.      * @param jsonFactory the factory to use
  359.      * @param objectMapper the current mapper instance
  360.      * @param tokenizeArrays if {@code true} and the "top level" JSON object is
  361.      * an array, each element is returned individually immediately after it is received
  362.      * @return the resulting token buffers
  363.      */
  364.     public static Flux<TokenBuffer> tokenize(Flux<DataBuffer> dataBuffers, JsonFactory jsonFactory,
  365.             ObjectMapper objectMapper, boolean tokenizeArrays, int maxInMemorySize) {
  366.  
  367.         try {
  368.             JsonParser parser = jsonFactory.createNonBlockingByteArrayParser();
  369.             DeserializationContext context = objectMapper.getDeserializationContext();
  370.             if (context instanceof DefaultDeserializationContext) {
  371.                 context = ((DefaultDeserializationContext) context).createInstance(
  372.                         objectMapper.getDeserializationConfig(), parser, objectMapper.getInjectableValues());
  373.             }
  374.             <span class="changed-code moved code-change-5">Jackson2Tokenizer</span> tokenizer = <span class="changed-code updated code-change-20">new <span class="changed-code moved code-change-4">Jackson2Tokenizer</span>(parser, context, tokenizeArrays, maxInMemorySize)</span>;
  375.             return dataBuffers.concatMapIterable(tokenizer::tokenize).concatWith(tokenizer.endOfInput());
  376.         }
  377.         catch (IOException ex) {
  378.             return Flux.error(ex);
  379.         }
  380.     }
  381.  
  382. }
  383.     </code>
  384.  
  385.     </figure>
  386.  
  387.     <div class="diff">
  388.         <div class="change change-addition" id="code-change-6">Insert ImportDeclaration to CompilationUnit at position 11</div><div class="change change-addition" id="code-change-7">Insert ImportDeclaration to CompilationUnit at position 21</div><div class="change change-move" id="code-change-0">Move FieldDeclaration to TypeDeclaration at position 11</div><div class="change change-move" id="code-change-1">Move FieldDeclaration to TypeDeclaration at position 6</div><div class="change change-addition" id="code-change-8">Insert FieldDeclaration to TypeDeclaration at position 6</div><div class="change change-addition" id="code-change-10">Insert MarkerAnnotation to FieldDeclaration at position 0</div><div class="change change-move" id="code-change-3">Move FieldAccess to MethodInvocation at position 0</div><div class="change change-update" id="code-change-19">Update Assignment with
  389.         INS FieldAccess to Assignment: = at 0
  390.         INS SimpleName: forceUseOfBigDecimal to Assignment: = at 1
  391.         INS ThisExpression to FieldAccess at 0
  392.         INS SimpleName: forceUseOfBigDecimal to FieldAccess at 1
  393. </div><div class="change change-delete" id="code-change-15">Remove ClassInstanceCreation</div><div class="change change-addition" id="code-change-11">Insert SingleVariableDeclaration to MethodDeclaration at position 5</div><div class="change change-addition" id="code-change-12">Insert ExpressionStatement to Block at position 6</div><div class="change change-addition" id="code-change-18">Insert Block to IfStatement at position 2</div><div class="change change-delete" id="code-change-17">Remove Assignment</div><div class="change change-addition" id="code-change-16">Insert MethodInvocation to ExpressionStatement at position 0</div><div class="change change-move" id="code-change-2">Move ExpressionStatement to Block at position 0</div><div class="change change-addition" id="code-change-13">Insert ExpressionStatement to Block at position 1</div><div class="change change-addition" id="code-change-9">Insert MethodDeclaration Partial to TypeDeclaration at position 20</div><div class="change change-move" id="code-change-5">Move SimpleType to ClassInstanceCreation at position 0</div><div class="change change-update" id="code-change-20">Update ClassInstanceCreation with
  394.         INS SimpleName: forceUseOfBigDecimal to ClassInstanceCreation at 4
  395. </div><div class="change change-move" id="code-change-4">Move SimpleType to VariableDeclarationStatement at position 0</div><div class="change change-addition" id="code-change-14">Insert VariableDeclarationStatement to Block at position 3</div>
  396.     </div>
  397.  
  398.     <figure class="code">
  399.         <figcaption>After:</figcaption>
  400.  
  401.     <code>
  402. /*
  403.  * Copyright 2002-2020 the original author or authors.
  404.  *
  405.  * Licensed under the Apache License, Version 2.0 (the "License");
  406.  * you may not use this file except in compliance with the License.
  407.  * You may obtain a copy of the License at
  408.  *
  409.  *      https://www.apache.org/licenses/LICENSE-2.0
  410.  *
  411.  * Unless required by applicable law or agreed to in writing, software
  412.  * distributed under the License is distributed on an "AS IS" BASIS,
  413.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  414.  * See the License for the specific language governing permissions and
  415.  * limitations under the License.
  416.  */
  417.  
  418. package org.springframework.http.codec.json;
  419.  
  420. import java.io.IOException;
  421. import java.util.ArrayList;
  422. import java.util.List;
  423. import java.util.function.Function;
  424.  
  425. import com.fasterxml.jackson.core.JsonFactory;
  426. import com.fasterxml.jackson.core.JsonParser;
  427. import com.fasterxml.jackson.core.JsonProcessingException;
  428. import com.fasterxml.jackson.core.JsonToken;
  429. import com.fasterxml.jackson.core.async.ByteArrayFeeder;
  430. import com.fasterxml.jackson.databind.DeserializationContext;
  431. <span class="changed-code added code-change-6">import com.fasterxml.jackson.databind.DeserializationFeature;</span>
  432. import com.fasterxml.jackson.databind.ObjectMapper;
  433. import com.fasterxml.jackson.databind.deser.DefaultDeserializationContext;
  434. import com.fasterxml.jackson.databind.util.TokenBuffer;
  435. import reactor.core.Exceptions;
  436. import reactor.core.publisher.Flux;
  437.  
  438. import org.springframework.core.codec.DecodingException;
  439. import org.springframework.core.io.buffer.DataBuffer;
  440. import org.springframework.core.io.buffer.DataBufferLimitException;
  441. import org.springframework.core.io.buffer.DataBufferUtils;
  442. <span class="changed-code added code-change-7">import org.springframework.lang.Nullable;</span>
  443.  
  444. /**
  445.  * {@link Function} to transform a JSON stream of arbitrary size, byte array
  446.  * chunks into a {@code Flux<TokenBuffer>} where each token buffer is a
  447.  * well-formed JSON object.
  448.  *
  449.  * @author Arjen Poutsma
  450.  * @author Rossen Stoyanchev
  451.  * @author Juergen Hoeller
  452.  * @since 5.0
  453.  */
  454. final class Jackson2Tokenizer {
  455.  
  456.     private final JsonParser parser;
  457.  
  458.     private final DeserializationContext deserializationContext;
  459.  
  460.     private final boolean tokenizeArrayElements;
  461.  
  462.     <span class="changed-code added code-change-8">private final boolean forceUseOfBigDecimal;</span>
  463.  
  464.     <span class="changed-code moved code-change-1">private final int maxInMemorySize;</span>
  465.  
  466.     private int objectDepth;
  467.  
  468.     private int arrayDepth;
  469.  
  470.     private int byteCount;
  471.  
  472.     <span class="changed-code moved code-change-0"><span class="changed-code added code-change-10">@Nullable</span> // yet initialized by calling createToken() in the constructor
  473.     private TokenBuffer tokenBuffer;</span>
  474.  
  475.  
  476.     // TODO: change to ByteBufferFeeder when supported by Jackson
  477.     // See https://github.com/FasterXML/jackson-core/issues/478
  478.     private final ByteArrayFeeder inputFeeder;
  479.  
  480.  
  481.     private Jackson2Tokenizer(JsonParser parser, DeserializationContext deserializationContext,
  482.             boolean tokenizeArrayElements, <span class="changed-code added code-change-11">boolean forceUseOfBigDecimal</span>, int maxInMemorySize) {
  483.  
  484.         this.parser = parser;
  485.         this.deserializationContext = deserializationContext;
  486.         this.tokenizeArrayElements = tokenizeArrayElements;
  487.         <span class="changed-code updated code-change-19">this.forceUseOfBigDecimal = forceUseOfBigDecimal</span>;
  488.         this.inputFeeder = (ByteArrayFeeder) this.parser.getNonBlockingInputFeeder();
  489.         this.maxInMemorySize = maxInMemorySize;
  490.         <span class="changed-code added code-change-12">createToken();</span>
  491.     }
  492.  
  493.  
  494.  
  495.     private List<TokenBuffer> tokenize(DataBuffer dataBuffer) {
  496.         int bufferSize = dataBuffer.readableByteCount();
  497.         byte[] bytes = new byte[bufferSize];
  498.         dataBuffer.read(bytes);
  499.         DataBufferUtils.release(dataBuffer);
  500.  
  501.         try {
  502.             this.inputFeeder.feedInput(bytes, 0, bytes.length);
  503.             List<TokenBuffer> result = parseTokenBufferFlux();
  504.             assertInMemorySize(bufferSize, result);
  505.             return result;
  506.         }
  507.         catch (JsonProcessingException ex) {
  508.             throw new DecodingException("JSON decoding error: " + ex.getOriginalMessage(), ex);
  509.         }
  510.         catch (IOException ex) {
  511.             throw Exceptions.propagate(ex);
  512.         }
  513.     }
  514.  
  515.     private Flux<TokenBuffer> endOfInput() {
  516.         return Flux.defer(() -> {
  517.             this.inputFeeder.endOfInput();
  518.             try {
  519.                 return Flux.fromIterable(parseTokenBufferFlux());
  520.             }
  521.             catch (JsonProcessingException ex) {
  522.                 throw new DecodingException("JSON decoding error: " + ex.getOriginalMessage(), ex);
  523.             }
  524.             catch (IOException ex) {
  525.                 throw Exceptions.propagate(ex);
  526.             }
  527.         });
  528.     }
  529.  
  530.     private List<TokenBuffer> parseTokenBufferFlux() throws IOException {
  531.         List<TokenBuffer> result = new ArrayList<>();
  532.  
  533.         // SPR-16151: Smile data format uses null to separate documents
  534.         boolean previousNull = false;
  535.         while (!this.parser.isClosed()) {
  536.             JsonToken token = this.parser.nextToken();
  537.             if (token == JsonToken.NOT_AVAILABLE ||
  538.                     token == null && previousNull) {
  539.                 break;
  540.             }
  541.             else if (token == null ) { // !previousNull
  542.                 previousNull = true;
  543.                 continue;
  544.             }
  545.             else <span class="changed-code added code-change-18">{
  546.                 previousNull = false;
  547.             }</span>
  548.             updateDepth(token);
  549.             if (!this.tokenizeArrayElements) {
  550.                 processTokenNormal(token, result);
  551.             }
  552.             else {
  553.                 processTokenArray(token, result);
  554.             }
  555.         }
  556.         return result;
  557.     }
  558.  
  559.     private void updateDepth(JsonToken token) {
  560.         switch (token) {
  561.             case START_OBJECT:
  562.                 this.objectDepth++;
  563.                 break;
  564.             case END_OBJECT:
  565.                 this.objectDepth--;
  566.                 break;
  567.             case START_ARRAY:
  568.                 this.arrayDepth++;
  569.                 break;
  570.             case END_ARRAY:
  571.                 this.arrayDepth--;
  572.                 break;
  573.         }
  574.     }
  575.  
  576.     private void processTokenNormal(JsonToken token, List<TokenBuffer> result) throws IOException {
  577.         this.tokenBuffer.copyCurrentEvent(this.parser);
  578.  
  579.         if ((token.isStructEnd() || token.isScalarValue()) && this.objectDepth == 0 && this.arrayDepth == 0) {
  580.             result.add(this.tokenBuffer);
  581.             <span class="changed-code added code-change-16">createToken()</span>;
  582.         }
  583.  
  584.     }
  585.  
  586.     private void processTokenArray(JsonToken token, List<TokenBuffer> result) throws IOException {
  587.         if (!isTopLevelArrayToken(token)) {
  588.             this.tokenBuffer.copyCurrentEvent(this.parser);
  589.         }
  590.  
  591.         if (this.objectDepth == 0 && (this.arrayDepth == 0 || this.arrayDepth == 1) &&
  592.                 (token == JsonToken.END_OBJECT || token.isScalarValue())) {
  593.             result.add(this.tokenBuffer);
  594.             <span class="changed-code added code-change-13">createToken();</span>
  595.         }
  596.     }
  597.  
  598.     <span class="changed-code added code-change-9">private void createToken() {
  599.         <span class="changed-code moved code-change-2">this.tokenBuffer = new TokenBuffer(this.parser, this.deserializationContext);</span>
  600.         <span class="changed-code moved code-change-3">this.tokenBuffer</span>.forceUseOfBigDecimal(this.forceUseOfBigDecimal);
  601.     }</span>
  602.  
  603.     private boolean isTopLevelArrayToken(JsonToken token) {
  604.         return this.objectDepth == 0 && ((token == JsonToken.START_ARRAY && this.arrayDepth == 1) ||
  605.                 (token == JsonToken.END_ARRAY && this.arrayDepth == 0));
  606.     }
  607.  
  608.     private void assertInMemorySize(int currentBufferSize, List<TokenBuffer> result) {
  609.         if (this.maxInMemorySize >= 0) {
  610.             if (!result.isEmpty()) {
  611.                 this.byteCount = 0;
  612.             }
  613.             else if (currentBufferSize > Integer.MAX_VALUE - this.byteCount) {
  614.                 raiseLimitException();
  615.             }
  616.             else {
  617.                 this.byteCount += currentBufferSize;
  618.                 if (this.byteCount > this.maxInMemorySize) {
  619.                     raiseLimitException();
  620.                 }
  621.             }
  622.         }
  623.     }
  624.  
  625.     private void raiseLimitException() {
  626.         throw new DataBufferLimitException(
  627.                 "Exceeded limit on max bytes per JSON object: " + this.maxInMemorySize);
  628.     }
  629.  
  630.  
  631.     /**
  632.      * Tokenize the given {@code Flux<DataBuffer>} into {@code Flux<TokenBuffer>}.
  633.      * @param dataBuffers the source data buffers
  634.      * @param jsonFactory the factory to use
  635.      * @param objectMapper the current mapper instance
  636.      * @param tokenizeArrays if {@code true} and the "top level" JSON object is
  637.      * an array, each element is returned individually immediately after it is received
  638.      * @return the resulting token buffers
  639.      */
  640.     public static Flux<TokenBuffer> tokenize(Flux<DataBuffer> dataBuffers, JsonFactory jsonFactory,
  641.             ObjectMapper objectMapper, boolean tokenizeArrays, int maxInMemorySize) {
  642.  
  643.         try {
  644.             JsonParser parser = jsonFactory.createNonBlockingByteArrayParser();
  645.             DeserializationContext context = objectMapper.getDeserializationContext();
  646.             if (context instanceof DefaultDeserializationContext) {
  647.                 context = ((DefaultDeserializationContext) context).createInstance(
  648.                         objectMapper.getDeserializationConfig(), parser, objectMapper.getInjectableValues());
  649.             }
  650.             <span class="changed-code added code-change-14">boolean forceUseOfBigDecimal = objectMapper.isEnabled(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);</span>
  651.             <span class="changed-code moved code-change-4">Jackson2Tokenizer</span> tokenizer = <span class="changed-code updated code-change-20">new <span class="changed-code moved code-change-5">Jackson2Tokenizer</span>(parser, context, tokenizeArrays, forceUseOfBigDecimal,
  652.                     maxInMemorySize)</span>;
  653.             return dataBuffers.concatMapIterable(tokenizer::tokenize).concatWith(tokenizer.endOfInput());
  654.         }
  655.         catch (IOException ex) {
  656.             return Flux.error(ex);
  657.         }
  658.     }
  659.  
  660. }
  661.     </code>
  662.  
  663.     </figure>
  664.  
  665.  
  666. </div>
  667.  
  668. <script type="text/javascript">
  669.     function drawLine(start, end, line, color = 'rgb(0, 0, 0)') {
  670.         let x1 = start.getBoundingClientRect().left;
  671.         let y1 = start.offsetTop + start.getBoundingClientRect().height / 2;
  672.         let x2 = end.getBoundingClientRect().left;
  673.         let y2 = end.getBoundingClientRect().top + window.scrollY + end.clientHeight / 2;
  674.  
  675.         if (x1 < x2) { // code is to the left
  676.            x1 += start.getBoundingClientRect().width;
  677.        } else {
  678.            x2 += end.clientWidth;
  679.        }
  680.  
  681.        document.documentElement.style.setProperty('--line-color', setAlpha(color, 1));
  682.        line.setAttribute('x1', x1);
  683.        line.setAttribute('y1', y1);
  684.        line.setAttribute('x2', x2);
  685.        line.setAttribute('y2', y2);
  686.    }
  687.  
  688.    function setChangedCodeListeners(changedCode, line) {
  689.        for (let elem of changedCode) {
  690.            elem.addEventListener('mouseenter', function () {
  691.                let changeId = elem.className.split(' ').find((v) => v.startsWith('code-change-'));
  692.  
  693.                 const start = elem;
  694.                 const end = document.getElementById(changeId);
  695.  
  696.                 console.log(start);
  697.                 drawLine(start, end, line);
  698.             });
  699.             console.log(elem.offsetTop)
  700.         }
  701.     }
  702.  
  703.     function setAlpha(rgba, alpha) {
  704.         console.log(rgba);
  705.         if (rgba.startsWith('rgba')) {
  706.             return rgba.replace(/ ([^ ]*)\)/, alpha);
  707.         } else {
  708.             return rgba.replace('rgb', 'rgba').replace(/(\))/, ', ' + alpha + ')');
  709.         }
  710.     }
  711.  
  712.     function setChangesListListeners(changesList, line, line2) {
  713.         for (let elem of changesList) {
  714.             let codeChanges = document.getElementsByClassName(elem.id);
  715.  
  716.             elem.addEventListener('mouseenter', function () {
  717.                 for (let change of codeChanges) {
  718.                     console.log("Enter", change.style.backgroundColor);
  719.                     change.style.backgroundColor = setAlpha(document.defaultView.getComputedStyle(change, null)['background-color'], 1);
  720.                 }
  721.  
  722.                 if (elem.className.includes('change-addition')) {
  723.                     drawLine(codeChanges[0], elem, line, 'var(--add-color)');
  724.                 } else if (elem.className.includes('change-move')) {
  725.                     drawLine(codeChanges[0], elem, line, 'var(--move-color)');
  726.                     drawLine(codeChanges[1], elem, line2, 'var(--move-color)');
  727.                 } else if (elem.className.includes('change-delete')) {
  728.                     drawLine(codeChanges[0], elem, line, 'var(--delete-color)');
  729.                 } else if (elem.className.includes('change-update')) {
  730.                     drawLine(codeChanges[0], elem, line, 'var(--update-color)');
  731.                     drawLine(codeChanges[1], elem, line2, 'var(--update-color)');
  732.                 }
  733.             });
  734.  
  735.             elem.addEventListener('mouseout', function () {
  736.                 for (let change of codeChanges) {
  737.                     line.setAttribute('x1', 0);
  738.                     line.setAttribute('y1', 0);
  739.                     line.setAttribute('x2', 0);
  740.                     line.setAttribute('y2', 0);
  741.                     line2.setAttribute('x1', 0);
  742.                     line2.setAttribute('y1', 0);
  743.                     line2.setAttribute('x2', 0);
  744.                     line2.setAttribute('y2', 0);
  745.                     console.log("Exit", change.style.backgroundColor);
  746.                     change.style.backgroundColor = setAlpha(document.defaultView.getComputedStyle(change, null)['background-color'], 0.3);
  747.                 }
  748.             });
  749.         }
  750.     }
  751.  
  752.     function positionChanges(changes, changedCode) {
  753.         const diffContainer = document.getElementsByClassName('diff')[0];
  754.         const codeChange = document.getElementsByClassName(changes[0].id)[0];
  755.         changes[0].style.top = (codeChange.offsetTop - diffContainer.offsetTop) + 'px';
  756.         for (let i = 1; i < changes.length; i++) {
  757.            const codeChange = document.getElementsByClassName(changes[i].id)[0];
  758.            console.log(codeChange.offsetTop + " positioning");
  759.            changes[i].style.top = Math.max(codeChange.offsetTop - diffContainer.offsetTop, changes[i - 1].offsetTop + changes[i - 1].offsetHeight + 10) + 'px';
  760.        }
  761.    }
  762.  
  763.    const changedCode = document.getElementsByClassName('changed-code');
  764.    const changesList = document.getElementsByClassName('change');
  765.    console.log(changedCode.length);
  766.  
  767.    const line = document.getElementById('line');
  768.    const line2 = document.getElementById('line2');
  769.  
  770.    positionChanges(changesList, changedCode);
  771.    setChangedCodeListeners(changedCode, line);
  772.    setChangesListListeners(changesList, line, line2);
  773. </script>
  774. </body>
  775. </html>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement