Coverage Report - org.apache.johnzon.core.JsonGeneratorImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
JsonGeneratorImpl
62%
225/359
55%
77/140
3,167
JsonGeneratorImpl$1
100%
1/1
N/A
3,167
JsonGeneratorImpl$StructureElement
100%
4/4
N/A
3,167
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements. See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership. The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License. You may obtain a copy of the License at
 9  
  *
 10  
  * http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied. See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package org.apache.johnzon.core;
 20  
 
 21  
 import java.io.IOException;
 22  
 import java.io.OutputStream;
 23  
 import java.io.OutputStreamWriter;
 24  
 import java.io.Serializable;
 25  
 import java.io.Writer;
 26  
 import java.math.BigDecimal;
 27  
 import java.math.BigInteger;
 28  
 import java.nio.charset.Charset;
 29  
 import java.util.Iterator;
 30  
 import java.util.Map;
 31  
 import java.util.concurrent.ConcurrentMap;
 32  
 
 33  
 import javax.json.JsonArray;
 34  
 import javax.json.JsonException;
 35  
 import javax.json.JsonNumber;
 36  
 import javax.json.JsonObject;
 37  
 import javax.json.JsonString;
 38  
 import javax.json.JsonStructure;
 39  
 import javax.json.JsonValue;
 40  
 import javax.json.stream.JsonGenerationException;
 41  
 import javax.json.stream.JsonGenerator;
 42  
 
 43  
 class JsonGeneratorImpl implements JsonGenerator, JsonChars, Serializable {
 44  1
     private static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
 45  
 
 46  
     private final transient Writer writer;
 47  
     private final BufferStrategy.BufferProvider<char[]> bufferProvider;
 48  
     private final char[] buffer;
 49  23
     private int bufferPos = 0;
 50  
     //private final ConcurrentMap<String, String> cache;
 51  23
     protected boolean needComma = false;
 52  
 
 53  23
     private StructureElement currentStructureElement = null;
 54  23
     private boolean valid = false;
 55  23
     protected int depth = 0;
 56  
 
 57  
     //minimal stack implementation
 58  
     private static final class StructureElement implements Serializable{
 59  
         final StructureElement previous;
 60  
         final boolean isArray;
 61  
 
 62  
         StructureElement(final StructureElement previous, final boolean isArray) {
 63  32
             super();
 64  32
             this.previous = previous;
 65  32
             this.isArray = isArray;
 66  32
         }
 67  
     }
 68  
 
 69  
     JsonGeneratorImpl(final Writer writer, final BufferStrategy.BufferProvider<char[]> bufferProvider,
 70  23
             final ConcurrentMap<String, String> cache) {
 71  23
         this.writer = writer;
 72  
         //this.cache = cache;
 73  23
         this.buffer = bufferProvider.newBuffer();
 74  23
         this.bufferProvider = bufferProvider;
 75  23
     }
 76  
 
 77  
     JsonGeneratorImpl(final OutputStream out, final BufferStrategy.BufferProvider<char[]> bufferProvider,
 78  
             final ConcurrentMap<String, String> cache) {
 79  22
         this(new OutputStreamWriter(out, UTF8_CHARSET), bufferProvider, cache);
 80  22
     }
 81  
 
 82  
     JsonGeneratorImpl(final OutputStream out, final Charset encoding, final BufferStrategy.BufferProvider<char[]> bufferProvider,
 83  
             final ConcurrentMap<String, String> cache) {
 84  0
         this(new OutputStreamWriter(out, encoding), bufferProvider, cache);
 85  0
     }
 86  
 
 87  
     protected void addCommaIfNeeded() {
 88  103
         if (needComma) {
 89  32
             justWrite(COMMA_CHAR);
 90  32
             needComma = false;
 91  
         }
 92  
 
 93  103
     }
 94  
 
 95  
     //caching currently disabled
 96  
     //two problems:
 97  
     // 1) not easy to get the escaped value efficiently wen its streamed and the buffer is full and needs to be flushed
 98  
     // 2) we have to use a kind of bounded threadsafe map to let the cache not grow indefinitely
 99  
     private void writeCachedOrEscape(final String name) {
 100  
       /*  String k = cache.get(name);
 101  
         
 102  
         if (k == null) {
 103  
                 
 104  
                 justWrite(QUOTE_CHAR);
 105  
                 int start = bufferPos;
 106  
                 writeEscaped0(name);
 107  
                 int end = bufferPos;
 108  
                 String escaped= get from buffer
 109  
                 ---
 110  
                 //FIXME if buffer is flushed this will not work here
 111  
                 cache.putIfAbsent(name, escaped);
 112  
                 justWrite(QUOTE_CHAR);
 113  
                 justWrite(KEY_SEPARATOR);
 114  
         }else*/
 115  
         {
 116  43
             justWrite(QUOTE_CHAR);
 117  43
             writeEscaped0(name);
 118  43
             justWrite(QUOTE_CHAR);
 119  43
             justWrite(KEY_SEPARATOR);
 120  
         }
 121  
 
 122  43
     }
 123  
 
 124  
     @Override
 125  
     public JsonGenerator writeStartObject() {
 126  
 
 127  15
         if (currentStructureElement == null && valid) {
 128  1
             throw new JsonGenerationException("Method must not be called more than once in no context");
 129  
         }
 130  
 
 131  14
         if (currentStructureElement != null && !currentStructureElement.isArray) {
 132  1
             throw new JsonGenerationException("Method must not be called within an object context");
 133  
         }
 134  
 
 135  
         //push upon the stack
 136  13
         if (currentStructureElement == null) {
 137  5
             currentStructureElement = new StructureElement(null, false);
 138  
         } else {
 139  8
             final StructureElement localStructureElement = new StructureElement(currentStructureElement, false);
 140  8
             currentStructureElement = localStructureElement;
 141  
         }
 142  
 
 143  13
         if (!valid) {
 144  5
             valid = true;
 145  
         }
 146  
 
 147  13
         noCheckWrite(START_OBJECT_CHAR);
 148  13
         depth++;
 149  13
         return this;
 150  
     }
 151  
 
 152  
     @Override
 153  
     public JsonGenerator writeStartObject(final String name) {
 154  3
         if (currentStructureElement == null || currentStructureElement.isArray) {
 155  1
             throw new JsonGenerationException("Method must not be called within an array context");
 156  
         }
 157  
 
 158  
         //push upon the stack
 159  2
         final StructureElement localStructureElement = new StructureElement(currentStructureElement, false);
 160  2
         currentStructureElement = localStructureElement;
 161  
 
 162  2
         addCommaIfNeeded();
 163  2
         writeCachedOrEscape(name);
 164  2
         noCheckWrite(START_OBJECT_CHAR);
 165  2
         depth++;
 166  2
         return this;
 167  
     }
 168  
 
 169  
     @Override
 170  
     public JsonGenerator writeStartArray() {
 171  15
         if (currentStructureElement == null && valid) {
 172  0
             throw new JsonGenerationException("Method must not be called more than once in no context");
 173  
         }
 174  
 
 175  15
         if (currentStructureElement != null && !currentStructureElement.isArray) {
 176  0
             throw new JsonGenerationException("Method must not be called within an object context");
 177  
         }
 178  
 
 179  
         //push upon the stack
 180  15
         if (currentStructureElement == null) {
 181  14
             currentStructureElement = new StructureElement(null, true);
 182  
         } else {
 183  1
             final StructureElement localStructureElement = new StructureElement(currentStructureElement, true);
 184  1
             currentStructureElement = localStructureElement;
 185  
         }
 186  
 
 187  15
         if (!valid) {
 188  14
             valid = true;
 189  
         }
 190  
 
 191  15
         noCheckWrite(START_ARRAY_CHAR);
 192  15
         depth++;
 193  15
         return this;
 194  
     }
 195  
 
 196  
     @Override
 197  
     public JsonGenerator writeStartArray(final String name) {
 198  3
         if (currentStructureElement == null || currentStructureElement.isArray) {
 199  1
             throw new JsonGenerationException("Method must not be called within an array context");
 200  
         }
 201  
         
 202  
         //push upon the stack
 203  2
         final StructureElement localStructureElement = new StructureElement(currentStructureElement, true);
 204  2
         currentStructureElement = localStructureElement;
 205  
 
 206  2
         addCommaIfNeeded();
 207  2
         writeCachedOrEscape(name);
 208  2
         noCheckWrite(START_ARRAY_CHAR);
 209  2
         depth++;
 210  2
         return this;
 211  
     }
 212  
 
 213  
     private void writeJsonValue(final String name, final JsonValue value) {
 214  4
         if (currentStructureElement != null) {
 215  4
             checkObject();
 216  
         }
 217  
         //TODO check null handling
 218  1
         switch (value.getValueType()) {
 219  
             case ARRAY:
 220  0
                 writeStartArray(name);
 221  0
                 final JsonArray array = JsonArray.class.cast(value);
 222  0
                 final Iterator<JsonValue> ait = array.iterator();
 223  0
                 while (ait.hasNext()) {
 224  0
                     write(ait.next());
 225  
                 }
 226  0
                 writeEnd();
 227  
 
 228  0
                 break;
 229  
             case OBJECT:
 230  0
                 writeStartObject(name);
 231  0
                 final JsonObject object = JsonObject.class.cast(value);
 232  0
                 final Iterator<Map.Entry<String, JsonValue>> oit = object.entrySet().iterator();
 233  0
                 while (oit.hasNext()) {
 234  0
                     final Map.Entry<String, JsonValue> keyval = oit.next();
 235  0
                     write(keyval.getKey(), keyval.getValue());
 236  0
                 }
 237  0
                 writeEnd();
 238  
 
 239  0
                 break;
 240  
             case STRING:
 241  4
                 write(name, JsonString.class.cast(value).getString());
 242  4
                 break;
 243  
             case NUMBER:
 244  
                 //TODO optimize
 245  0
                 final JsonNumber number = JsonNumber.class.cast(value);
 246  0
                 if (number.isIntegral()) {
 247  0
                     write(name, number.longValueExact());
 248  
                 } else {
 249  0
                     write(name, number.bigDecimalValue());
 250  
                 }
 251  0
                 break;
 252  
             case TRUE:
 253  0
                 write(name, true);
 254  0
                 break;
 255  
             case FALSE:
 256  0
                 write(name, false);
 257  0
                 break;
 258  
             case NULL:
 259  0
                 writeNull(name);
 260  0
                 break;
 261  
             default:
 262  0
                 throw new JsonGenerationException("Unknown JsonValue type");
 263  
         }
 264  4
     }
 265  
 
 266  
     private void writeJsonValue(final JsonValue value) {
 267  4
         if (currentStructureElement != null) {
 268  3
             checkArray();
 269  
         }
 270  
         //TODO check null handling
 271  4
         switch (value.getValueType()) {
 272  
             case ARRAY:
 273  0
                 writeStartArray();
 274  0
                 final JsonArray array = JsonArray.class.cast(value);
 275  0
                 final Iterator<JsonValue> ait = array.iterator();
 276  0
                 while (ait.hasNext()) {
 277  0
                     write(ait.next());
 278  
                 }
 279  0
                 writeEnd();
 280  
 
 281  0
                 break;
 282  
             case OBJECT:
 283  1
                 writeStartObject();
 284  1
                 final JsonObject object = JsonObject.class.cast(value);
 285  1
                 final Iterator<Map.Entry<String, JsonValue>> oit = object.entrySet().iterator();
 286  2
                 while (oit.hasNext()) {
 287  1
                     final Map.Entry<String, JsonValue> keyval = oit.next();
 288  1
                     write(keyval.getKey(), keyval.getValue());
 289  1
                 }
 290  1
                 writeEnd();
 291  
 
 292  1
                 break;
 293  
             case STRING:
 294  0
                 write(JsonString.class.cast(value).getString());
 295  0
                 break;
 296  
             case NUMBER:
 297  
                 //TODO optimize
 298  0
                 final JsonNumber number = JsonNumber.class.cast(value);
 299  0
                 if (number.isIntegral()) {
 300  0
                     write(number.longValueExact());
 301  
                 } else {
 302  0
                     write(number.bigDecimalValue());
 303  
                 }
 304  0
                 break;
 305  
             case TRUE:
 306  1
                 write(true);
 307  1
                 break;
 308  
             case FALSE:
 309  1
                 write(false);
 310  1
                 break;
 311  
             case NULL:
 312  1
                 writeNull();
 313  1
                 break;
 314  
             default:
 315  0
                 throw new JsonGenerationException("Unknown JsonValue type");
 316  
         }
 317  4
     }
 318  
 
 319  
     @Override
 320  
     public JsonGenerator write(final String name, final JsonValue value) {
 321  4
         writeJsonValue(name, value);
 322  4
         return this;
 323  
     }
 324  
 
 325  
 
 326  
     @Override
 327  
     public JsonGenerator write(final String name, final String value) {
 328  24
         checkObject();
 329  
 
 330  24
         addCommaIfNeeded();
 331  24
         writeCachedOrEscape(name);
 332  
 
 333  24
         addCommaIfNeeded();
 334  24
         justWrite(QUOTE_CHAR);
 335  24
         writeEscaped0(value);
 336  24
         justWrite(QUOTE_CHAR);
 337  24
         needComma = true;
 338  24
         return this;
 339  
     }
 340  
 
 341  
     @Override
 342  
     public JsonGenerator write(final String name, final BigInteger value) {
 343  3
         checkObject();
 344  3
         addCommaIfNeeded();
 345  3
         writeCachedOrEscape(name);
 346  3
         noCheckWriteAndForceComma(String.valueOf(value));
 347  3
         return this;
 348  
     }
 349  
 
 350  
     @Override
 351  
     public JsonGenerator write(final String name, final BigDecimal value) {
 352  3
         checkObject();
 353  3
         addCommaIfNeeded();
 354  3
         writeCachedOrEscape(name);
 355  3
         noCheckWriteAndForceComma(String.valueOf(value));
 356  3
         return this;
 357  
     }
 358  
 
 359  
     @Override
 360  
     public JsonGenerator write(final String name, final int value) {
 361  5
         checkObject();
 362  4
         addCommaIfNeeded();
 363  4
         writeCachedOrEscape(name);
 364  4
         addCommaIfNeeded();
 365  4
         writeInt0(value);
 366  4
         needComma = true;
 367  4
         return this;
 368  
     }
 369  
 
 370  
     @Override
 371  
     public JsonGenerator write(final String name, final long value) {
 372  2
         checkObject();
 373  2
         addCommaIfNeeded();
 374  2
         writeCachedOrEscape(name);
 375  2
         addCommaIfNeeded();
 376  2
         writeLong0(value);
 377  2
         needComma = true;
 378  2
         return this;
 379  
     }
 380  
 
 381  
     @Override
 382  
     public JsonGenerator write(final String name, final double value) {
 383  0
         checkObject();
 384  0
         checkDoubleRange(value);
 385  0
         addCommaIfNeeded();
 386  0
         writeCachedOrEscape(name);
 387  0
         noCheckWriteAndForceComma(String.valueOf(value));
 388  0
         return this;
 389  
     }
 390  
 
 391  
     @Override
 392  
     public JsonGenerator write(final String name, final boolean value) {
 393  3
         checkObject();
 394  3
         addCommaIfNeeded();
 395  3
         writeCachedOrEscape(name);
 396  3
         noCheckWriteAndForceComma(String.valueOf(value));
 397  3
         return this;
 398  
     }
 399  
 
 400  
     @Override
 401  
     public JsonGenerator writeNull(final String name) {
 402  0
         checkObject();
 403  0
         addCommaIfNeeded();
 404  0
         writeCachedOrEscape(name);
 405  0
         noCheckWriteAndForceComma(NULL);
 406  0
         return this;
 407  
     }
 408  
 
 409  
     @Override
 410  
     public JsonGenerator writeEnd() {
 411  30
         if (currentStructureElement == null) {
 412  1
             throw new JsonGenerationException("Method must not be called in no context");
 413  
         }
 414  
 
 415  29
         writeEnd(currentStructureElement.isArray ? END_ARRAY_CHAR : END_OBJECT_CHAR);
 416  
 
 417  
         //pop from stack
 418  29
         currentStructureElement = currentStructureElement.previous;
 419  29
         depth--;
 420  
 
 421  29
         return this;
 422  
     }
 423  
 
 424  
     @Override
 425  
     public JsonGenerator write(final JsonValue value) {
 426  4
         writeJsonValue(value);
 427  
 
 428  4
         if (JsonStructure.class.isInstance(value)) {
 429  1
             valid = true;
 430  
         }
 431  4
         return this;
 432  
     }
 433  
 
 434  
     @Override
 435  
     public JsonGenerator write(final String value) {
 436  7
         checkArray();
 437  7
         addCommaIfNeeded();
 438  7
         justWrite(QUOTE_CHAR);
 439  7
         writeEscaped0(value);
 440  7
         justWrite(QUOTE_CHAR);
 441  7
         needComma = true;
 442  7
         return this;
 443  
     }
 444  
 
 445  
 
 446  
     @Override
 447  
     public JsonGenerator write(final BigDecimal value) {
 448  0
         checkArray();
 449  0
         noCheckWrite(String.valueOf(value));
 450  0
         needComma = true;
 451  0
         return this;
 452  
     }
 453  
 
 454  
     @Override
 455  
     public JsonGenerator write(final BigInteger value) {
 456  0
         checkArray();
 457  0
         noCheckWrite(String.valueOf(value));
 458  0
         needComma = true;
 459  0
         return this;
 460  
     }
 461  
 
 462  
     @Override
 463  
     public JsonGenerator write(final int value) {
 464  2
         checkArray();
 465  2
         addCommaIfNeeded();
 466  2
         writeInt0(value);
 467  2
         needComma = true;
 468  2
         return this;
 469  
     }
 470  
 
 471  
     @Override
 472  
     public JsonGenerator write(final long value) {
 473  0
         checkArray();
 474  0
         addCommaIfNeeded();
 475  0
         writeLong0(value);
 476  0
         needComma = true;
 477  0
         return this;
 478  
     }
 479  
 
 480  
     @Override
 481  
     public JsonGenerator write(final double value) {
 482  0
         checkArray();
 483  0
         checkDoubleRange(value);
 484  0
         noCheckWrite(Double.toString(value));
 485  0
         needComma = true;
 486  0
         return this;
 487  
     }
 488  
 
 489  
     @Override
 490  
     public JsonGenerator write(final boolean value) {
 491  2
         checkArray();
 492  2
         noCheckWrite(Boolean.toString(value));
 493  2
         needComma = true;
 494  2
         return this;
 495  
     }
 496  
 
 497  
     @Override
 498  
     public JsonGenerator writeNull() {
 499  7
         checkArray();
 500  7
         noCheckWriteAndForceComma(NULL);
 501  7
         needComma = true;
 502  7
         return this;
 503  
     }
 504  
 
 505  
     @Override
 506  
     public void close() {
 507  
 
 508  
         try {
 509  17
             if (currentStructureElement != null || !valid) {
 510  
 
 511  2
                 throw new JsonGenerationException("Invalid json " + currentStructureElement + " " + valid);
 512  
             }
 513  
         } finally {
 514  
 
 515  17
             flushBuffer();
 516  
 
 517  
             try {
 518  17
                 writer.close();
 519  0
             } catch (final IOException e) {
 520  0
                 throw new JsonException(e.getMessage(), e);
 521  17
             }
 522  
 
 523  17
             bufferProvider.release(buffer);
 524  15
         }
 525  15
     }
 526  
 
 527  
     @Override
 528  
     public void flush() {
 529  
 
 530  0
         flushBuffer();
 531  
 
 532  
         try {
 533  0
             writer.flush();
 534  0
         } catch (final IOException e) {
 535  0
             throw new JsonException(e.getMessage(), e);
 536  0
         }
 537  0
     }
 538  
 
 539  
     private JsonGenerator noCheckWriteAndForceComma(final String value) {
 540  16
         noCheckWrite(value);
 541  16
         needComma = true;
 542  16
         return this;
 543  
     }
 544  
 
 545  
     protected JsonGenerator writeEnd(final char value) {
 546  29
         justWrite(value);
 547  29
         needComma = true;
 548  29
         return this;
 549  
     }
 550  
 
 551  
     protected void noCheckWrite(final String value) {
 552  18
         addCommaIfNeeded();
 553  18
         justWrite(value);
 554  18
     }
 555  
 
 556  
     protected void noCheckWrite(final char value) {
 557  32
         addCommaIfNeeded();
 558  32
         justWrite(value);
 559  32
     }
 560  
 
 561  
     private void flushBuffer() {
 562  
 
 563  17
         if (bufferPos > 0) {
 564  
 
 565  
             try {
 566  16
                 writer.write(buffer, 0, bufferPos);
 567  16
                 bufferPos = 0;
 568  0
             } catch (final IOException e) {
 569  0
                 throw new JsonException(e.getMessage(), e);
 570  16
             }
 571  
 
 572  
         }
 573  17
     }
 574  
 
 575  
     private void writeEscaped0(final String value) {
 576  74
         int len = 0;
 577  74
         if (value == null || (len = value.length()) == 0) {
 578  1
             return;
 579  
         }
 580  
 
 581  80
         for (int i = 0; i < value.length(); i++) {
 582  77
             char c = value.charAt(i);
 583  
 
 584  390
             while (c != ESCAPE_CHAR && c != QUOTE_CHAR && c >= SPACE) {
 585  
                 
 586  
                 //read fast
 587  383
                 justWrite(c);
 588  
 
 589  383
                 if (i >= len - 1) {
 590  70
                     return;
 591  
                 }
 592  
 
 593  313
                 i++;
 594  313
                 c = value.charAt(i);
 595  
             }
 596  
 
 597  7
             switch (c) {
 598  
                 case QUOTE_CHAR:
 599  
                 case ESCAPE_CHAR:
 600  4
                     justWrite(ESCAPE_CHAR);
 601  4
                     justWrite(c);
 602  4
                     break;
 603  
                 default:
 604  3
                     if (c < SPACE) {
 605  3
                         switch (c) {
 606  
                             case EOL:
 607  0
                                 justWrite("\\n");
 608  0
                                 break;
 609  
                             case '\r':
 610  0
                                 justWrite("\\r");
 611  0
                                 break;
 612  
                             case '\t':
 613  2
                                 justWrite("\\t");
 614  2
                                 break;
 615  
                             case '\b':
 616  0
                                 justWrite("\\b");
 617  0
                                 break;
 618  
                             case '\f':
 619  0
                                 justWrite("\\f");
 620  0
                                 break;
 621  
                             default:
 622  1
                                 justWrite(toUnicode(c));
 623  
                         }
 624  0
                     } else if ((c >= '\u0080' && c < '\u00a0') || (c >= '\u2000' && c < '\u2100')) {
 625  0
                         justWrite(toUnicode(c));
 626  
                     } else {
 627  0
                         justWrite(c);
 628  
                     }
 629  
             }
 630  
         }
 631  
 
 632  3
     }
 633  
 
 634  
     private static final String UNICODE_PREFIX = "\\u";
 635  
     private static final String UNICODE_PREFIX_HELPER = "000";
 636  
 
 637  
     private static String toUnicode(final char c) {
 638  
 
 639  1
         final String hex = UNICODE_PREFIX_HELPER + Integer.toHexString(c);
 640  1
         final String s = UNICODE_PREFIX + hex.substring(hex.length() - 4);
 641  
 
 642  1
         return s;
 643  
     }
 644  
 
 645  
     protected void justWrite(final char[] chars) {
 646  
 
 647  0
         if (bufferPos + chars.length >= buffer.length) {
 648  
 
 649  0
             int start = 0;
 650  0
             int len = buffer.length - bufferPos;
 651  
 
 652  
             while (true) {
 653  0
                 int end = start + len;
 654  0
                 if (end > chars.length) {
 655  0
                     end = chars.length;
 656  
                 }
 657  
 
 658  0
                 System.arraycopy(chars, start, buffer, bufferPos, end - start);
 659  
 
 660  0
                 bufferPos += (end - start);
 661  0
                 start += (len);
 662  
 
 663  0
                 if (start >= chars.length) {
 664  0
                     return;
 665  
                 }
 666  
 
 667  0
                 if (bufferPos >= buffer.length) {
 668  0
                     flushBuffer();
 669  0
                     len = buffer.length;
 670  
                 }
 671  
 
 672  0
             }
 673  
 
 674  
         } else {
 675  
             //fits completely into the buffer
 676  0
             System.arraycopy(chars, 0, buffer, bufferPos, chars.length);
 677  0
             bufferPos += chars.length;
 678  
         }
 679  
 
 680  0
     }
 681  
 
 682  
     protected void justWrite(final String value) {
 683  64
         final int valueLength = value.length();
 684  
 
 685  64
         if (bufferPos + valueLength >= buffer.length) {
 686  
 
 687  0
             int start = 0;
 688  0
             int len = buffer.length - bufferPos;
 689  
 
 690  
             while (true) {
 691  0
                 int end = start + len;
 692  0
                 if (end > valueLength) {
 693  0
                     end = valueLength;
 694  
                 }
 695  
 
 696  0
                 value.getChars(start, end, buffer, bufferPos);
 697  
 
 698  0
                 bufferPos += (end - start);
 699  0
                 start += (len);
 700  
 
 701  0
                 if (start >= valueLength) {
 702  0
                     return;
 703  
                 }
 704  
 
 705  0
                 if (bufferPos >= buffer.length) {
 706  0
                     flushBuffer();
 707  0
                     len = buffer.length;
 708  
                 }
 709  
 
 710  0
             }
 711  
 
 712  
         } else {
 713  
             //fits completely into the buffer
 714  64
             value.getChars(0, valueLength, buffer, bufferPos);
 715  64
             bufferPos += valueLength;
 716  
         }
 717  
 
 718  64
     }
 719  
 
 720  
     protected void justWrite(final char value) {
 721  
 
 722  705
         if (bufferPos >= buffer.length) {
 723  0
             flushBuffer();
 724  
         }
 725  
 
 726  705
         buffer[bufferPos++] = value;
 727  
 
 728  705
     }
 729  
     
 730  
     private void checkObject() {
 731  44
         if (currentStructureElement == null || currentStructureElement.isArray) {
 732  1
             throw new JsonGenerationException("write(name, param) is only valid in objects");
 733  
         }
 734  43
     }
 735  
 
 736  
     private void checkArray() {
 737  21
         if (currentStructureElement == null || !currentStructureElement.isArray) {
 738  0
             throw new JsonGenerationException("write(param) is only valid in arrays");
 739  
         }
 740  21
     }
 741  
 
 742  
     private static void checkDoubleRange(final double value) {
 743  0
         if (Double.isInfinite(value) || Double.isNaN(value)) {
 744  0
             throw new NumberFormatException("double can't be infinite or NaN");
 745  
         }
 746  0
     }
 747  
     
 748  
     
 749  
     //unopitimized, see below
 750  
     private void writeLong0(final long i) {
 751  
 
 752  2
         justWrite(String.valueOf(i));
 753  2
     }
 754  
 
 755  
     //unopitimized, see below
 756  
     private void writeInt0(final int i) {
 757  
 
 758  6
         justWrite(String.valueOf(i));
 759  6
     }
 760  
     
 761  
     //optimized number optimizations
 762  
 /*
 763  
     private void writeLong0(final long i) {
 764  
         if (i == Long.MIN_VALUE) {
 765  
             justWrite("-9223372036854775808");
 766  
             return;
 767  
         }
 768  
         final int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
 769  
         final char[] buf = new char[size];
 770  
         getChars(i, size, buf);
 771  
         justWrite(buf);
 772  
     }
 773  
 
 774  
     private void writeInt0(final int i) {
 775  
         if (i == Integer.MIN_VALUE) {
 776  
             justWrite("-2147483648");
 777  
             return;
 778  
         }
 779  
         final int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
 780  
         final char[] buf = new char[size];
 781  
         getChars(i, size, buf);
 782  
         justWrite(buf);
 783  
     }
 784  
 
 785  
     private final static char[] DIGIT_TENS = { '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1',
 786  
             '1', '1', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', '4', '4', '4',
 787  
             '4', '4', '4', '4', '4', '4', '4', '5', '5', '5', '5', '5', '5', '5', '5', '5', '5', '6', '6', '6', '6', '6', '6', '6', '6',
 788  
             '6', '6', '7', '7', '7', '7', '7', '7', '7', '7', '7', '7', '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', '9', '9', '9',
 789  
             '9', '9', '9', '9', '9', '9', '9', };
 790  
 
 791  
     private final static char[] DIGIT_ONES = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7',
 792  
             '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2',
 793  
             '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7',
 794  
             '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2',
 795  
             '3', '4', '5', '6', '7', '8', '9', };
 796  
 
 797  
     private final static char[] DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
 798  
             'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
 799  
 
 800  
     // Requires positive x
 801  
     private static int stringSize(final long x) {
 802  
         long p = 10;
 803  
         for (int i = 1; i < 19; i++) {
 804  
             if (x < p) {
 805  
                 return i;
 806  
             }
 807  
             p = 10 * p;
 808  
         }
 809  
         return 19;
 810  
     }
 811  
 
 812  
     private static void getChars(long i, final int index, final char[] buf) {
 813  
         long q;
 814  
         int r;
 815  
         int charPos = index;
 816  
         char sign = 0;
 817  
 
 818  
         if (i < 0) {
 819  
             sign = '-';
 820  
             i = -i;
 821  
         }
 822  
 
 823  
         // Get 2 digits/iteration using longs until quotient fits into an int
 824  
         while (i > Integer.MAX_VALUE) {
 825  
             q = i / 100;
 826  
             // really: r = i - (q * 100);
 827  
             r = (int) (i - ((q << 6) + (q << 5) + (q << 2)));
 828  
             i = q;
 829  
             buf[--charPos] = DIGIT_ONES[r];
 830  
             buf[--charPos] = DIGIT_TENS[r];
 831  
         }
 832  
 
 833  
         // Get 2 digits/iteration using ints
 834  
         int q2;
 835  
         int i2 = (int) i;
 836  
         while (i2 >= 65536) {
 837  
             q2 = i2 / 100;
 838  
             // really: r = i2 - (q * 100);
 839  
             r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2));
 840  
             i2 = q2;
 841  
             buf[--charPos] = DIGIT_ONES[r];
 842  
             buf[--charPos] = DIGIT_TENS[r];
 843  
         }
 844  
 
 845  
         // Fall thru to fast mode for smaller numbers
 846  
         // assert(i2 <= 65536, i2);
 847  
         for (;;) {
 848  
             q2 = (i2 * 52429) >>> (16 + 3);
 849  
             r = i2 - ((q2 << 3) + (q2 << 1)); // r = i2-(q2*10) ...
 850  
             buf[--charPos] = DIGITS[r];
 851  
             i2 = q2;
 852  
             if (i2 == 0) {
 853  
                 break;
 854  
             }
 855  
         }
 856  
         if (sign != 0) {
 857  
             buf[--charPos] = sign;
 858  
         }
 859  
     }
 860  
 */
 861  
    
 862  
 }