Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  //========================================================================
  //Copyright 2007-2010 David Yu dyuproject@gmail.com
  //------------------------------------------------------------------------
  //Licensed under the Apache License, Version 2.0 (the "License");
  //you may not use this file except in compliance with the License.
  //You may obtain a copy of the License at 
  //http://www.apache.org/licenses/LICENSE-2.0
  //Unless required by applicable law or agreed to in writing, software
  //distributed under the License is distributed on an "AS IS" BASIS,
 //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 //See the License for the specific language governing permissions and
 //limitations under the License.
 //========================================================================
 
 package io.protostuff;
 
An optimized json output which is efficient in writing numeric keys and pre-encoded utf8 strings (in byte array form).

This is the appropriate output sink to use when writing from binary (protostuff,protobuf,etc) pipes.

Author(s):
David Yu
Created:
Jul 2, 2010
 
 public final class JsonXOutput extends WriteSession implements OutputStatefulOutput
 {
 
     private static final byte START_OBJECT = (byte'{'END_OBJECT = (byte'}',
             START_ARRAY = (byte'['END_ARRAY = (byte']',
             COMMA = (byte','QUOTE = (byte'"';
 
     private static final byte[] TRUE = new byte[] {
             (byte't', (byte'r', (byte'u', (byte'e'
     };
 
     private static final byte[] FALSE = new byte[] {
             (byte'f', (byte'a', (byte'l', (byte's', (byte'e'
     };
 
     private static final byte[] KEY_SUFFIX_ARRAY = new byte[] {
             (byte'"', (byte':', (byte'['
     };
 
     private static final byte[] KEY_SUFFIX_ARRAY_OBJECT = new byte[] {
             (byte'"', (byte':', (byte'[', (byte'{'
     };
 
     private static final byte[] KEY_SUFFIX_ARRAY_STRING = new byte[] {
             (byte'"', (byte':', (byte'[', (byte'"'
     };
 
     private static final byte[] KEY_SUFFIX_OBJECT = new byte[] {
             (byte'"', (byte':', (byte'{'
     };
 
     private static final byte[] KEY_SUFFIX_STRING = new byte[] {
             (byte'"', (byte':', (byte'"'
     };
 
     private static final byte[] KEY_SUFFIX = new byte[] {
             (byte'"', (byte':',
     };
 
     private static final byte[] COMMA_AND_QUOTE = new byte[] {
             (byte',', (byte'"',
     };
 
     private static final byte[] COMMA_AND_START_OBJECT = new byte[] {
             (byte',', (byte'{',
     };
 
     private static final byte[] END_ARRAY_AND_END_OBJECT = new byte[] {
             (byte']', (byte'}'
     };
 
     private static final byte[] END_ARRAY__COMMA__QUOTE = new byte[] {
             (byte']', (byte',', (byte'"'
     };
 
     private Schema<?> schema;
     private final boolean numeric;
     private boolean lastRepeated;
     private int lastNumber;
 
     public JsonXOutput(LinkedBuffer headboolean numericSchema<?> schema)
     {
         super(head);
         this. = numeric;
         this. = schema;
     }
 
     public JsonXOutput(LinkedBuffer headOutputStream out,
             FlushHandler flushHandlerint nextBufferSize,
             boolean numericSchema<?> schema)
    {
        super(headoutflushHandlernextBufferSize);
        this. = numeric;
        this. = schema;
    }
    public JsonXOutput(LinkedBuffer headOutputStream outboolean numeric,
            Schema<?> schema)
    {
        super(headout);
        this. = numeric;
        this. = schema;
    }

    
Resets this output for re-use.
    @Override
    public void reset()
    {
         = false;
         = 0;
    }
    @Override
    public JsonXOutput clear()
    {
        super.clear();
        return this;
    }

    
Before serializing a message/object tied to a schema, this should be called.
    public JsonXOutput use(Schema<?> schema)
    {
        this. = schema;
        return this;
    }

    
Returns whether the incoming messages' field names are numeric.
    public boolean isNumeric()
    {
        return ;
    }

    
Gets the last field number written.
    public int getLastNumber()
    {
        return ;
    }

    
Returns true if the last written field was a repeated field.
    public boolean isLastRepeated()
    {
        return ;
    }
    @Override
    public void updateLast(Schema<?> schemaSchema<?> lastSchema)
    {
        if (lastSchema != null && lastSchema == this.)
        {
            this. = schema;
        }
    }
    {
         = .writeByteArray(this);
        return this;
    }
    {
         = .writeByte(this);
        return this;
    }
    {
         = .writeByte(this);
        return this;
    }
    {
         = .writeByte(this);
        return this;
    }
    {
         = .writeByte(this);
        return this;
    }
    private LinkedBuffer writeKey(final int fieldNumberfinal WriteSink sink,
            final byte[] keySuffixthrows IOException
    {
        if ()
        {
            if ()
            {
                return sink.writeByteArray(
                        keySuffix,
                        this,
                        sink.writeStrFromInt(
                                fieldNumber,
                                this,
                                sink.writeByteArray(
                                        ,
                                        this,
                                        )));
            }
            if ( == 0)
            {
                return sink.writeByteArray(
                        keySuffix,
                        this,
                        sink.writeStrFromInt(
                                fieldNumber,
                                this,
                                sink.writeByte(
                                        ,
                                        this,
                                        )));
            }
            return sink.writeByteArray(
                    keySuffix,
                    this,
                    sink.writeStrFromInt(
                            fieldNumber,
                            this,
                            sink.writeByteArray(
                                    ,
                                    this,
                                    )));
        }
        if ()
        {
            return sink.writeByteArray(
                    keySuffix,
                    this,
                    sink.writeStrAscii(
                            .getFieldName(fieldNumber),
                            this,
                            sink.writeByteArray(
                                    ,
                                    this,
                                    )));
        }
        if ( == 0)
        {
            return sink.writeByteArray(
                    keySuffix,
                    this,
                    sink.writeStrAscii(
                            .getFieldName(fieldNumber),
                            this,
                            sink.writeByte(
                                    ,
                                    this,
                                    )));
        }
        return sink.writeByteArray(
                keySuffix,
                this,
                sink.writeStrAscii(
                        .getFieldName(fieldNumber),
                        this,
                        sink.writeByteArray(
                                ,
                                this,
                                )));
    }
    @Override
    public void writeBool(int fieldNumberboolean valueboolean repeatedthrows IOException
    {
        final WriteSink sink = this.;
        if ( == fieldNumber)
        {
            // repeated field
             = sink.writeByteArray(
                    value ?  : ,
                    this,
                    sink.writeByte(
                            ,
                            this,
                            ));
            return;
        }
         = sink.writeByteArray(
                value ?  : ,
                this,
                writeKey(
                        fieldNumber,
                        sink,
                        repeated ?  : ));
         = fieldNumber;
         = repeated;
    }
    @Override
    public void writeByteArray(int fieldNumberbyte[] valueboolean repeatedthrows IOException
    {
        final WriteSink sink = this.;
        if ( == fieldNumber)
        {
            // repeated field
             = sink.writeByte(
                    ,
                    this,
                    sink.writeByteArrayB64(
                            value, 0, value.length,
                            this,
                            sink.writeByteArray(
                                    ,
                                    this,
                                    )));
            return;
        }
         = sink.writeByte(
                ,
                this,
                sink.writeByteArrayB64(
                        value, 0, value.length,
                        this,
                        writeKey(
                                fieldNumber,
                                sink,
                                repeated ?  : )));
         = fieldNumber;
         = repeated;
    }
    @Override
    public void writeByteRange(boolean utf8Stringint fieldNumberbyte[] value,
            int offsetint lengthboolean repeatedthrows IOException
    {
        final WriteSink sink = this.;
        if (utf8String)
        {
            if ( == fieldNumber)
            {
                // repeated field
                 = sink.writeByte(
                        ,
                        this,
                        writeUTF8Escaped(
                                valueoffsetlength,
                                sink,
                                this,
                                sink.writeByteArray(
                                        ,
                                        this,
                                        )));
                return;
            }
             = sink.writeByte(
                    ,
                    this,
                    writeUTF8Escaped(
                            valueoffsetlength,
                            sink,
                            this,
                            writeKey(
                                    fieldNumber,
                                    sink,
                                    repeated ?  : )));
             = fieldNumber;
             = repeated;
            return;
        }
        if ( == fieldNumber)
        {
            // repeated field
             = sink.writeByte(
                    ,
                    this,
                    sink.writeByteArrayB64(
                            valueoffsetlength,
                            this,
                            sink.writeByteArray(
                                    ,
                                    this,
                                    )));
            return;
        }
         = sink.writeByte(
                ,
                this,
                sink.writeByteArrayB64(
                        valueoffsetlength,
                        this,
                        writeKey(
                                fieldNumber,
                                sink,
                                repeated ?  : )));
         = fieldNumber;
         = repeated;
    }
    @Override
    public void writeBytes(int fieldNumberByteString valueboolean repeatedthrows IOException
    {
        writeByteArray(fieldNumbervalue.getBytes(), repeated);
    }
    @Override
    public void writeDouble(int fieldNumberdouble valueboolean repeatedthrows IOException
    {
        final WriteSink sink = this.;
        if ( == fieldNumber)
        {
            // repeated field
             = sink.writeStrFromDouble(
                    value,
                    this,
                    sink.writeByte(
                            ,
                            this,
                            ));
            return;
        }
         = sink.writeStrFromDouble(
                value,
                this,
                writeKey(
                        fieldNumber,
                        sink,
                        repeated ?  : ));
         = fieldNumber;
         = repeated;
    }
    @Override
    public void writeEnum(int fieldNumberint valueboolean repeatedthrows IOException
    {
        writeInt32(fieldNumbervaluerepeated);
    }
    @Override
    public void writeFixed32(int fieldNumberint valueboolean repeatedthrows IOException
    {
        writeInt32(fieldNumbervaluerepeated);
    }
    @Override
    public void writeFixed64(int fieldNumberlong valueboolean repeatedthrows IOException
    {
        writeInt64(fieldNumbervaluerepeated);
    }
    @Override
    public void writeFloat(int fieldNumberfloat valueboolean repeatedthrows IOException
    {
        final WriteSink sink = this.;
        if ( == fieldNumber)
        {
            // repeated field
             = sink.writeStrFromFloat(
                    value,
                    this,
                    sink.writeByte(
                            ,
                            this,
                            ));
            return;
        }
         = sink.writeStrFromFloat(
                value,
                this,
                writeKey(
                        fieldNumber,
                        sink,
                        repeated ?  : ));
         = fieldNumber;
         = repeated;
    }
    @Override
    public void writeInt32(int fieldNumberint valueboolean repeatedthrows IOException
    {
        final WriteSink sink = this.;
        if ( == fieldNumber)
        {
            // repeated field
             = sink.writeStrFromInt(
                    value,
                    this,
                    sink.writeByte(
                            ,
                            this,
                            ));
            return;
        }
         = sink.writeStrFromInt(
                value,
                this,
                writeKey(
                        fieldNumber,
                        sink,
                        repeated ?  : ));
         = fieldNumber;
         = repeated;
    }
    @Override
    public void writeInt64(int fieldNumberlong valueboolean repeatedthrows IOException
    {
        final WriteSink sink = this.;
        if ( == fieldNumber)
        {
            // repeated field
             = sink.writeStrFromLong(
                    value,
                    this,
                    sink.writeByte(
                            ,
                            this,
                            ));
            return;
        }
         = sink.writeStrFromLong(
                value,
                this,
                writeKey(
                        fieldNumber,
                        sink,
                        repeated ?  : ));
         = fieldNumber;
         = repeated;
    }
    @Override
    public void writeSFixed32(int fieldNumberint valueboolean repeatedthrows IOException
    {
        writeInt32(fieldNumbervaluerepeated);
    }
    @Override
    public void writeSFixed64(int fieldNumberlong valueboolean repeatedthrows IOException
    {
        writeInt64(fieldNumbervaluerepeated);
    }
    @Override
    public void writeSInt32(int fieldNumberint valueboolean repeatedthrows IOException
    {
        writeInt32(fieldNumbervaluerepeated);
    }
    @Override
    public void writeSInt64(int fieldNumberlong valueboolean repeatedthrows IOException
    {
        writeInt64(fieldNumbervaluerepeated);
    }
    @Override
    public void writeString(int fieldNumberString valueboolean repeatedthrows IOException
    {
        final WriteSink sink = this.;
        if ( == fieldNumber)
        {
            // repeated field
             = sink.writeByte(
                    ,
                    this,
                    writeUTF8Escaped(
                            value,
                            sink,
                            this,
                            sink.writeByteArray(
                                    ,
                                    this,
                                    )));
            return;
        }
         = sink.writeByte(
                ,
                this,
                writeUTF8Escaped(
                        value,
                        sink,
                        this,
                        writeKey(
                                fieldNumber,
                                sink,
                                repeated ?  : )));
         = fieldNumber;
         = repeated;
    }
    @Override
    public void writeUInt32(int fieldNumberint valueboolean repeatedthrows IOException
    {
        writeInt32(fieldNumbervaluerepeated);
    }
    @Override
    public void writeUInt64(int fieldNumberlong valueboolean repeatedthrows IOException
    {
        writeInt64(fieldNumbervaluerepeated);
    }
    @Override
    public <T> void writeObject(final int fieldNumberfinal T valuefinal Schema<T> schema,
            final boolean repeatedthrows IOException
    {
        final WriteSink sink = this.;
        final Schema<?> lastSchema = this.;
        if ( == fieldNumber)
        {
             = sink.writeByteArray(
                    ,
                    this,
                    );
        }
        else
        {
             = writeKey(
                    fieldNumber,
                    sink,
                    repeated ?  : );
        }
        // reset
        this. = schema;
         = 0;
         = false;
        // recursive write
        schema.writeTo(thisvalue);
         =  ? sink.writeByteArray(this) :
                sink.writeByte(this);
        // restore state
         = fieldNumber;
         = repeated;
        this. = lastSchema;
    }
    private static LinkedBuffer writeUTF8Escaped(final byte[] inputint inStart,
            int inLenfinal WriteSink sinkfinal WriteSession session,
            LinkedBuffer lbthrows IOException
    {
        int lastStart = inStart;
        for (int i = 0; i < inLeni++)
        {
            final byte b = input[inStart++];
            if (b > 0x7f)
                continue;
            // ascii
            final int escape = [b];
            if (escape == 0)
            {
                // nothing to escape
                continue;
            }
            if (escape < 0)
            {
                // hex escape
                // dump the bytes before this offset.
                final int dumpLen = inStart - lastStart - 1;
                if (dumpLen != 0)
                    lb = sink.writeByteArray(inputlastStartdumpLensessionlb);
                // update
                lastStart = inStart;
                if (lb.offset + 6 > lb.buffer.length)
                    lb = sink.drain(sessionlb);
                final int value = -(escape + 1);
                lb.buffer[lb.offset++] = (byte'\\';
                lb.buffer[lb.offset++] = (byte'u';
                lb.buffer[lb.offset++] = (byte'0';
                lb.buffer[lb.offset++] = (byte'0';
                lb.buffer[lb.offset++] = [value >> 4];
                lb.buffer[lb.offset++] = [value & 0x0F];
                session.size += 6;
            }
            else
            {
                // dump the bytes before this offset.
                final int dumpLen = inStart - lastStart - 1;
                if (dumpLen != 0)
                    lb = sink.writeByteArray(inputlastStartdumpLensessionlb);
                // update
                lastStart = inStart;
                if (lb.offset + 2 > lb.buffer.length)
                    lb = sink.drain(sessionlb);
                lb.buffer[lb.offset++] = (byte'\\';
                lb.buffer[lb.offset++] = (byteescape;
                session.size += 2;
            }
        }
        final int remaining = inStart - lastStart;
        return remaining == 0 ? lb : sink.writeByteArray(inputlastStartremaining,
                sessionlb);
    }
    private static LinkedBuffer writeUTF8Escaped(final String strfinal WriteSink sink,
            final WriteSession sessionLinkedBuffer lbthrows IOException
    {
        final int len = str.length();
        if (len == 0)
            return lb;
        byte[] buffer = lb.buffer;
        int limit = buffer.lengthoffset = lb.offsetsize = len;
        for (int i = 0; i < leni++)
        {
            final char c = str.charAt(i);
            if (c < 0x0080)
            {
                final int escape = [c];
                // System.out.print(c + "|" + escape + " ");
                if (escape == 0)
                {
                    // nothing to escape
                    if (offset == limit)
                    {
                        lb.offset = offset;
                        lb = sink.drain(sessionlb);
                        offset = lb.offset;
                        buffer = lb.buffer;
                        limit = buffer.length;
                    }
                    // ascii
                    buffer[offset++] = (bytec;
                }
                else if (escape < 0)
                {
                    // hex escape
                    if (offset + 6 > limit)
                    {
                        lb.offset = offset;
                        lb = sink.drain(sessionlb);
                        offset = lb.offset;
                        buffer = lb.buffer;
                        limit = buffer.length;
                    }
                    final int value = -(escape + 1);
                    buffer[offset++] = (byte'\\';
                    buffer[offset++] = (byte'u';
                    buffer[offset++] = (byte'0';
                    buffer[offset++] = (byte'0';
                    buffer[offset++] = [value >> 4];
                    buffer[offset++] = [value & 0x0F];
                    size += 5;
                }
                else
                {
                    if (offset + 2 > limit)
                    {
                        lb.offset = offset;
                        lb = sink.drain(sessionlb);
                        offset = lb.offset;
                        buffer = lb.buffer;
                        limit = buffer.length;
                    }
                    buffer[offset++] = (byte'\\';
                    buffer[offset++] = (byteescape;
                    size++;
                }
            }
            else if (c < 0x0800)
            {
                if (offset + 2 > limit)
                {
                    lb.offset = offset;
                    lb = sink.drain(sessionlb);
                    offset = lb.offset;
                    buffer = lb.buffer;
                    limit = buffer.length;
                }
                buffer[offset++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
                buffer[offset++] = (byte) (0x80 | ((c >> 0) & 0x3F));
                size++;
            }
            else
            {
                if (offset + 3 > limit)
                {
                    lb.offset = offset;
                    lb = sink.drain(sessionlb);
                    offset = lb.offset;
                    buffer = lb.buffer;
                    limit = buffer.length;
                }
                buffer[offset++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
                buffer[offset++] = (byte) (0x80 | ((c >> 6) & 0x3F));
                buffer[offset++] = (byte) (0x80 | ((c >> 0) & 0x3F));
                size += 2;
            }
        }
        session.size += size;
        lb.offset = offset;
        return lb;
    }
    static final byte[] HEX_BYTES = new byte[] {
            (byte'0', (byte'1', (byte'2', (byte'3', (byte'4',
            (byte'5', (byte'6', (byte'7', (byte'8', (byte'9',
            (byte'A', (byte'B', (byte'C', (byte'D', (byte'E', (byte'F'
    };
    // jackson output escaping compabtility
    static final int[] sOutputEscapes;
    static
    {
        int[] table = new int[128];
        // Control chars need generic escape sequence
        for (int i = 0; i < 32; ++i)
        {
            table[i] = -(i + 1);
        }
        /*
         * Others (and some within that range too) have explicit shorter sequences
         */
        table['"'] = '"';
        table['\\'] = '\\';
        // Escaping of slash is optional, so let's not add it
        table[0x08] = 'b';
        table[0x09] = 't';
        table[0x0C] = 'f';
        table[0x0A] = 'n';
        table[0x0D] = 'r';
         = table;
    }

    
Writes a ByteBuffer field.
    @Override
    public void writeBytes(int fieldNumberByteBuffer valueboolean repeatedthrows IOException
    {
        writeByteRange(falsefieldNumbervalue.array(), value.arrayOffset() + value.position(),
                value.remaining(), repeated);
    }
New to GrepCode? Check out our FAQ X