package com.jsoniter.output; import com.jsoniter.any.Any; import com.jsoniter.spi.*; import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.Type; public class JsonStream extends OutputStream { public Config configCache; int indention = 0; private OutputStream out; byte buf[]; int count; public JsonStream(OutputStream out, int bufSize) { if (bufSize < 32) { throw new JsonException("buffer size must be larger than 32: " + bufSize); } this.out = out; this.buf = new byte[bufSize]; } public void reset(OutputStream out) { this.out = out; this.count = 0; } final void ensure(int minimal) throws IOException { int available = buf.length - count; if (available < minimal) { if (count > 1024) { flushBuffer(); } growAtLeast(minimal); } } private final void growAtLeast(int minimal) { int toGrow = buf.length; if (toGrow < minimal) { toGrow = minimal; } byte[] newBuf = new byte[buf.length + toGrow]; System.arraycopy(buf, 0, newBuf, 0, buf.length); buf = newBuf; } public final void write(int b) throws IOException { ensure(1); buf[count++] = (byte) b; } public final void write(byte b1, byte b2) throws IOException { ensure(2); buf[count++] = b1; buf[count++] = b2; } public final void write(byte b1, byte b2, byte b3) throws IOException { ensure(3); buf[count++] = b1; buf[count++] = b2; buf[count++] = b3; } public final void write(byte b1, byte b2, byte b3, byte b4) throws IOException { ensure(4); buf[count++] = b1; buf[count++] = b2; buf[count++] = b3; buf[count++] = b4; } public final void write(byte b1, byte b2, byte b3, byte b4, byte b5) throws IOException { ensure(5); buf[count++] = b1; buf[count++] = b2; buf[count++] = b3; buf[count++] = b4; buf[count++] = b5; } public final void write(byte b1, byte b2, byte b3, byte b4, byte b5, byte b6) throws IOException { ensure(6); buf[count++] = b1; buf[count++] = b2; buf[count++] = b3; buf[count++] = b4; buf[count++] = b5; buf[count++] = b6; } public final void write(byte b[], int off, int len) throws IOException { if (out == null) { ensure(len); } else { if (len >= buf.length - count) { if (len >= buf.length) { /* If the request length exceeds the size of the output buffer, flush the output buffer and then write the data directly. In this way buffered streams will cascade harmlessly. */ flushBuffer(); out.write(b, off, len); return; } flushBuffer(); } } System.arraycopy(b, off, buf, count, len); count += len; } public void flush() throws IOException { flushBuffer(); out.flush(); } @Override public void close() throws IOException { if (out == null) { return; } if (count > 0) { flushBuffer(); } out.close(); this.out = null; count = 0; } final void flushBuffer() throws IOException { if (out == null) { return; } out.write(buf, 0, count); count = 0; } public final void writeVal(String val) throws IOException { if (val == null) { writeNull(); } else { StreamImplString.writeString(this, val); } } public final void writeRaw(String val) throws IOException { writeRaw(val, val.length()); } public final void writeRaw(String val, int remaining) throws IOException { if (out == null) { ensure(remaining); val.getBytes(0, remaining, buf, count); count += remaining; return; } int i = 0; for (; ; ) { int available = buf.length - count; if (available < remaining) { remaining -= available; int j = i + available; val.getBytes(i, j, buf, count); count = buf.length; flushBuffer(); i = j; } else { int j = i + remaining; val.getBytes(i, j, buf, count); count += remaining; return; } } } public final void writeVal(Boolean val) throws IOException { if (val == null) { writeNull(); } else { if (val) { writeTrue(); } else { writeFalse(); } } } public final void writeVal(boolean val) throws IOException { if (val) { writeTrue(); } else { writeFalse(); } } public final void writeTrue() throws IOException { write((byte) 't', (byte) 'r', (byte) 'u', (byte) 'e'); } public final void writeFalse() throws IOException { write((byte) 'f', (byte) 'a', (byte) 'l', (byte) 's', (byte) 'e'); } public final void writeVal(Short val) throws IOException { if (val == null) { writeNull(); } else { writeVal(val.intValue()); } } public final void writeVal(short val) throws IOException { writeVal((int) val); } public final void writeVal(Integer val) throws IOException { if (val == null) { writeNull(); } else { writeVal(val.intValue()); } } public final void writeVal(int val) throws IOException { StreamImplNumber.writeInt(this, val); } public final void writeVal(Long val) throws IOException { if (val == null) { writeNull(); } else { writeVal(val.longValue()); } } public final void writeVal(long val) throws IOException { StreamImplNumber.writeLong(this, val); } public final void writeVal(Float val) throws IOException { if (val == null) { writeNull(); } else { writeVal(val.floatValue()); } } public final void writeVal(float val) throws IOException { StreamImplNumber.writeFloat(this, val); } public final void writeVal(Double val) throws IOException { if (val == null) { writeNull(); } else { writeVal(val.doubleValue()); } } public final void writeVal(double val) throws IOException { StreamImplNumber.writeDouble(this, val); } public final void writeVal(Any val) throws IOException { val.writeTo(this); } public final void writeNull() throws IOException { write((byte) 'n', (byte) 'u', (byte) 'l', (byte) 'l'); } public final void writeEmptyObject() throws IOException { write((byte) '{', (byte) '}'); } public final void writeEmptyArray() throws IOException { write((byte) '[', (byte) ']'); } public final void writeArrayStart() throws IOException { indention += currentConfig().indentionStep(); write('['); } public final void writeMore() throws IOException { write(','); writeIndention(); } public void writeIndention() throws IOException { writeIndention(0); } private void writeIndention(int delta) throws IOException { if (indention == 0) { return; } write('\n'); int toWrite = indention - delta; ensure(toWrite); for (int i = 0; i < toWrite && count < buf.length; i++) { buf[count++] = ' '; } } public final void writeArrayEnd() throws IOException { int indentionStep = currentConfig().indentionStep(); writeIndention(indentionStep); indention -= indentionStep; write(']'); } public final void writeObjectStart() throws IOException { int indentionStep = currentConfig().indentionStep(); indention += indentionStep; write('{'); } public final void writeObjectField(String field) throws IOException { writeVal(field); if (indention > 0) { write((byte) ':', (byte) ' '); } else { write(':'); } } public final void writeObjectField(Object key) throws IOException { Encoder encoder = MapKeyEncoders.registerOrGetExisting(key.getClass()); writeObjectField(key, encoder); } public final void writeObjectField(Object key, Encoder keyEncoder) throws IOException { keyEncoder.encode(key, this); if (indention > 0) { write((byte) ':', (byte) ' '); } else { write(':'); } } public final void writeObjectEnd() throws IOException { int indentionStep = currentConfig().indentionStep(); writeIndention(indentionStep); indention -= indentionStep; write('}'); } public final void writeVal(Object obj) throws IOException { if (obj == null) { writeNull(); return; } Class<?> clazz = obj.getClass(); String cacheKey = currentConfig().getEncoderCacheKey(clazz); Codegen.getEncoder(cacheKey, clazz).encode(obj, this); } public final <T> void writeVal(TypeLiteral<T> typeLiteral, T obj) throws IOException { if (null == obj) { writeNull(); } else { Config config = currentConfig(); String cacheKey = config.getEncoderCacheKey(typeLiteral.getType()); Codegen.getEncoder(cacheKey, typeLiteral.getType()).encode(obj, this); } } public final <T> void writeVal(Type type, T obj) throws IOException { if (null == obj) { writeNull(); } else { Config config = currentConfig(); String cacheKey = config.getEncoderCacheKey(type); Codegen.getEncoder(cacheKey, type).encode(obj, this); } } public Config currentConfig() { if (configCache != null) { return configCache; } configCache = JsoniterSpi.getCurrentConfig(); return configCache; } public static void serialize(Config config, Object obj, OutputStream out) { JsoniterSpi.setCurrentConfig(config); try { serialize(obj, out); } finally { JsoniterSpi.clearCurrentConfig(); } } public static void serialize(Object obj, OutputStream out) { JsonStream stream = JsonStreamPool.borrowJsonStream(); try { try { stream.reset(out); stream.writeVal(obj); } finally { stream.close(); } } catch (IOException e) { throw new JsonException(e); } finally { JsonStreamPool.returnJsonStream(stream); } } public static void serialize(Config config, TypeLiteral typeLiteral, Object obj, OutputStream out) { JsoniterSpi.setCurrentConfig(config); try { serialize(typeLiteral, obj, out); } finally { JsoniterSpi.clearCurrentConfig(); } } public static void serialize(TypeLiteral typeLiteral, Object obj, OutputStream out) { JsonStream stream = JsonStreamPool.borrowJsonStream(); try { try { stream.reset(out); stream.writeVal(typeLiteral, obj); } finally { stream.close(); } } catch (IOException e) { throw new JsonException(e); } finally { JsonStreamPool.returnJsonStream(stream); } } public static void serialize(Type type, Object obj, OutputStream out) { JsonStream stream = JsonStreamPool.borrowJsonStream(); try { try { stream.reset(out); stream.writeVal(type, obj); } finally { stream.close(); } } catch (IOException e) { throw new JsonException(e); } finally { JsonStreamPool.returnJsonStream(stream); } } public static String serialize(Config config, Object obj) { JsoniterSpi.setCurrentConfig(config); try { return serialize(config.escapeUnicode(), obj.getClass(), obj); } finally { JsoniterSpi.clearCurrentConfig(); } } public static String serialize(Object obj) { return serialize(JsoniterSpi.getCurrentConfig().escapeUnicode(), obj.getClass(), obj); } public static String serialize(Config config, TypeLiteral typeLiteral, Object obj) { JsoniterSpi.setCurrentConfig(config); try { return serialize(config.escapeUnicode(), typeLiteral.getType(), obj); } finally { JsoniterSpi.clearCurrentConfig(); } } public static String serialize(TypeLiteral typeLiteral, Object obj) { return serialize(JsoniterSpi.getCurrentConfig().escapeUnicode(), typeLiteral.getType(), obj); } public static String serialize(boolean escapeUnicode, Type type, Object obj) { JsonStream stream = JsonStreamPool.borrowJsonStream(); try { stream.reset(null); stream.writeVal(type, obj); if (escapeUnicode) { return new String(stream.buf, 0, stream.count); } else { return new String(stream.buf, 0, stream.count, "UTF8"); } } catch (IOException e) { throw new JsonException(e); } finally { JsonStreamPool.returnJsonStream(stream); } } public static void setMode(EncodingMode mode) { Config newConfig = JsoniterSpi.getDefaultConfig().copyBuilder().encodingMode(mode).build(); JsoniterSpi.setDefaultConfig(newConfig); JsoniterSpi.setCurrentConfig(newConfig); } public static void setIndentionStep(int indentionStep) { Config newConfig = JsoniterSpi.getDefaultConfig().copyBuilder().indentionStep(indentionStep).build(); JsoniterSpi.setDefaultConfig(newConfig); JsoniterSpi.setCurrentConfig(newConfig); } public static void registerNativeEncoder(Class clazz, Encoder.ReflectionEncoder encoder) { CodegenImplNative.NATIVE_ENCODERS.put(clazz, encoder); } public Slice buffer() { return new Slice(buf, 0, count); } }