From 9223198c6f2eb130113074888b2d61fb7b7a3ce3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=9C=B0=E5=B9=B3=E7=BA=BF?= <22250530@qq.com> Date: Fri, 6 Nov 2015 17:02:06 +0800 Subject: [PATCH] --- .../convert/json/JsonByteBufferWriter.java | 260 ++++++++++++++++++ .../redkale/convert/json/JsonConvert.java | 33 +++ .../redkale/convert/json/JsonWriter.java | 177 +++++------- .../wentch/redkale/net/http/HttpContext.java | 4 + .../wentch/redkale/net/http/HttpResponse.java | 11 +- src/com/wentch/redkale/util/Utility.java | 15 +- 6 files changed, 393 insertions(+), 107 deletions(-) create mode 100644 src/com/wentch/redkale/convert/json/JsonByteBufferWriter.java diff --git a/src/com/wentch/redkale/convert/json/JsonByteBufferWriter.java b/src/com/wentch/redkale/convert/json/JsonByteBufferWriter.java new file mode 100644 index 000000000..7cecade31 --- /dev/null +++ b/src/com/wentch/redkale/convert/json/JsonByteBufferWriter.java @@ -0,0 +1,260 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.wentch.redkale.convert.json; + +import com.wentch.redkale.util.*; +import java.nio.*; +import java.nio.charset.*; +import java.util.*; +import java.util.function.*; + +/** + * + * @author zhangjx + */ +public class JsonByteBufferWriter extends JsonWriter { + + private static final Charset UTF8 = Charset.forName("UTF-8"); + + private final Charset charset; + + private final Supplier supplier; + + private ByteBuffer[] buffers; + + private int index; + + public JsonByteBufferWriter(Supplier supplier) { + this(null, supplier); + } + + public JsonByteBufferWriter(Charset charset, Supplier supplier) { + this.charset = UTF8.equals(charset) ? null : charset; + this.supplier = supplier; + } + + @Override + protected boolean recycle() { + this.index = 0; + this.buffers = null; + return true; + } + + public ByteBuffer[] toBuffers() { + if (buffers == null) return new ByteBuffer[0]; + for (int i = index; i < this.buffers.length; i++) { + this.buffers[i].flip(); + } + return this.buffers; + } + + @Override + public char[] toArray() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public byte[] toUTF8Bytes() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int count() { + if (this.buffers == null) return 0; + int len = 0; + for (ByteBuffer buffer : buffers) { + len += buffer.remaining(); + } + return len; + } + + private void expand(final int byteLength) { + if (this.buffers == null) { + this.index = 0; + this.buffers = new ByteBuffer[]{supplier.get()}; + } + ByteBuffer buffer = this.buffers[index]; + if (!buffer.hasRemaining()) { + buffer.flip(); + buffer = supplier.get(); + ByteBuffer[] bufs = new ByteBuffer[this.buffers.length + 1]; + System.arraycopy(this.buffers, 0, bufs, 0, this.buffers.length); + bufs[this.buffers.length] = buffer; + this.buffers = bufs; + this.index++; + } + if (buffer.remaining() >= byteLength) return; + int len = buffer.remaining(); + while (len < byteLength) { + buffer = supplier.get(); + ByteBuffer[] bufs = new ByteBuffer[this.buffers.length + 1]; + System.arraycopy(this.buffers, 0, bufs, 0, this.buffers.length); + bufs[this.buffers.length] = buffer; + this.buffers = bufs; + len += buffer.remaining(); + } + } + + @Override + public void writeTo(final char ch) { + if (ch > Byte.MAX_VALUE) throw new RuntimeException("writeTo char(int.value = " + (int) ch + ") must be less 127"); + expand(1); + this.buffers[index].put((byte) ch); + } + + @Override + public void writeTo(final char[] chs, final int start, final int len) { + writeTo(false, chs, start, len); + } + + private void writeTo(final boolean quote, final char[] chs, final int start, final int len) { + int byteLength = quote ? 2 : 0; + ByteBuffer bb = null; + if (charset == null) { + byteLength += encodeUTF8Length(chs, start, len); + } else { + bb = charset.encode(CharBuffer.wrap(chs, start, len)); + byteLength += bb.remaining(); + } + expand(byteLength); + ByteBuffer buffer = this.buffers[index]; + if (quote) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '"'); + } + if (charset == null) { //UTF-8 + final int limit = start + len; + for (int i = start; i < limit; i++) { + buffer = putChar(buffer, chs[i]); + } + } else { + while (bb.hasRemaining()) { + buffer.put(bb.get()); + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + } + } + if (quote) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '"'); + } + } + + private ByteBuffer putChar(ByteBuffer buffer, char c) { + if (c < 0x80) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) c); + } else if (c < 0x800) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) (0xc0 | (c >> 6))); + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) (0x80 | (c & 0x3f))); + } else { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) (0xe0 | ((c >> 12)))); + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) (0x80 | ((c >> 6) & 0x3f))); + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) (0x80 | (c & 0x3f))); + } + return buffer; + } + + private ByteBuffer nextByteBuffer() { + this.buffers[this.index].flip(); + return this.buffers[++this.index]; + } + + private static int encodeUTF8Length(final char[] text, final int start, final int len) { + char c; + int size = 0; + final char[] chars = text; + final int limit = start + len; + for (int i = start; i < limit; i++) { + c = chars[i]; + size += (c < 0x80 ? 1 : (c < 0x800 ? 2 : 3)); + } + return size; + } + + /** + * 注意: 该String值不能为null且不会进行转义, 只用于不含需要转义字符的字符串,例如enum、double、BigInteger转换的String + * + * @param quote + * @param value + */ + @Override + public void writeTo(final boolean quote, final String value) { + char[] chs = Utility.charArray(value); + writeTo(quote, chs, 0, chs.length); + } + + @Override + public void writeString(String value) { + if (value == null) { + writeNull(); + return; + } + final char[] chs = Utility.charArray(value); + int len = 0; + for (char ch : chs) { + switch (ch) { + case '\n': len += 2; + break; + case '\r': len += 2; + break; + case '\t': len += 2; + break; + case '\\': len += 2; + break; + case '"': len += 2; + break; + default: len++; + break; + } + } + if (len == chs.length) { + writeTo(true, chs, 0, len); + } else { + StringBuilder sb = new StringBuilder(value.length() * 2); + for (char ch : chs) { + switch (ch) { + case '\n': sb.append("\\n"); + break; + case '\r': sb.append("\\r"); + break; + case '\t': sb.append("\\t"); + break; + case '\\': sb.append("\\\\"); + break; + case '"': sb.append("\\\""); + break; + default: sb.append(ch); + ; + break; + } + } + char[] cs = Utility.charArray(sb); + writeTo(true, cs, 0, sb.length()); + } + } + + @Override + public void writeField(boolean comma, Attribute attribute) { + if (comma) writeTo(','); + writeTo(true, attribute.field()); + writeTo(':'); + } + + @Override + public void writeSmallString(String value) { + writeTo(false, value); + } + + @Override + public String toString() { + return Objects.toString(this); + } +} diff --git a/src/com/wentch/redkale/convert/json/JsonConvert.java b/src/com/wentch/redkale/convert/json/JsonConvert.java index 10b64d5e1..5f7ef298f 100644 --- a/src/com/wentch/redkale/convert/json/JsonConvert.java +++ b/src/com/wentch/redkale/convert/json/JsonConvert.java @@ -8,6 +8,9 @@ package com.wentch.redkale.convert.json; import com.wentch.redkale.convert.*; import com.wentch.redkale.util.*; import java.lang.reflect.*; +import java.nio.*; +import java.nio.charset.*; +import java.util.function.*; /** * @@ -94,6 +97,36 @@ public final class JsonConvert extends Convert { } } + public ByteBuffer[] convertTo(final Supplier supplier, final Type type, Object value) { + return convertTo(null, supplier, type, value); + } + + public ByteBuffer[] convertTo(final Charset charset, final Supplier supplier, final Type type, Object value) { + if (supplier == null || type == null) return null; + JsonByteBufferWriter out = new JsonByteBufferWriter(charset, supplier); + if (value == null) { + out.writeNull(); + } else { + factory.loadEncoder(type).convertTo(out, value); + } + return out.toBuffers(); + } + + public ByteBuffer[] convertTo(final Supplier supplier, Object value) { + return convertTo(null, supplier, value); + } + + public ByteBuffer[] convertTo(final Charset charset, final Supplier supplier, Object value) { + if (supplier == null) return null; + JsonByteBufferWriter out = new JsonByteBufferWriter(charset, supplier); + if (value == null) { + out.writeNull(); + } else { + factory.loadEncoder(value.getClass()).convertTo(out, value); + } + return out.toBuffers(); + } + public byte[] convertToUTF8Bytes(Object value) { if (value == null) return new byte[]{110, 117, 108, 108}; return convertToUTF8Bytes(value.getClass(), value); diff --git a/src/com/wentch/redkale/convert/json/JsonWriter.java b/src/com/wentch/redkale/convert/json/JsonWriter.java index ec67e5cd8..1b18456dc 100644 --- a/src/com/wentch/redkale/convert/json/JsonWriter.java +++ b/src/com/wentch/redkale/convert/json/JsonWriter.java @@ -22,7 +22,7 @@ public class JsonWriter implements Writer { private static final int defaultSize = Integer.getInteger("convert.json.writer.buffer.defsize", 1024); - protected int count; + private int count; private char[] content; @@ -58,7 +58,7 @@ public class JsonWriter implements Writer { * @param len * @return */ - public char[] expand(int len) { + private char[] expand(int len) { int newcount = count + len; if (newcount <= content.length) return content; char[] newdata = new char[Math.max(content.length * 3 / 2, newcount)]; @@ -67,20 +67,12 @@ public class JsonWriter implements Writer { return newdata; } - public void writeTo(final char ch) { + public void writeTo(final char ch) { //只能是 0 - 127 的字符 expand(1); content[count++] = ch; } - public void writeTo(final char... chs) { - int len = chs.length; - expand(len); - System.arraycopy(chs, 0, content, count, len); - count += len; - } - - public void writeTo(final char[] chs, final int start, final int end) { - int len = end - start; + public void writeTo(final char[] chs, final int start, final int len) { //只能是 0 - 127 的字符 expand(len); System.arraycopy(chs, start, content, count, len); count += len; @@ -120,77 +112,10 @@ public class JsonWriter implements Writer { return Utility.encodeUTF8(content, 0, count); } - //------------------------------------------------------------------------ - public final int count() { + public int count() { return this.count; } - public final void count(int count) { - if (count >= 0) this.count = count; - } - -// @SuppressWarnings("unchecked") -// public final boolean writeRefer(final Object value) { -// if (stack == null) return false; -// int index = stack.indexOf(value); -// if (index > -1) { -// int deep = stack.size() - index; -// if (deep < 0) throw new ConvertException("the refer deep value(" + deep + ") is illegal"); -// writeTo('{', '"', '@', '"', ':', '"'); -// for (int i = 0; i < deep; i++) { -// writeTo('@'); -// } -// writeTo('"', '}'); -// return true; -// } -// return false; -// } - //----------------------------------------------------------------------- - @Override - public String toString() { - return new String(content, 0, count); - } - - @Override - public void writeBoolean(boolean value) { - writeTo(value ? CHARS_TUREVALUE : CHARS_FALSEVALUE); - } - - @Override - public void writeByte(byte value) { - writeInt(value); - } - - @Override - public void writeChar(char value) { - writeInt(value); - } - - @Override - public void writeShort(short value) { - writeInt(value); - } - - @Override - public void writeInt(int value) { - writeSmallString(String.valueOf(value)); - } - - @Override - public void writeLong(long value) { - writeSmallString(String.valueOf(value)); - } - - @Override - public void writeFloat(float value) { - writeSmallString(String.valueOf(value)); - } - - @Override - public void writeDouble(double value) { - writeSmallString(String.valueOf(value)); - } - @Override public void writeString(String value) { if (value == null) { @@ -224,7 +149,71 @@ public class JsonWriter implements Writer { } @Override - public void wirteClassName(String clazz) { + public void writeField(boolean comma, Attribute attribute) { + if (comma) writeTo(','); + writeTo('"'); + writeSmallString(attribute.field()); + writeTo('"'); + writeTo(':'); + } + + @Override + public void writeSmallString(String value) { + writeTo(false, value); + } + + @Override + public String toString() { + return new String(content, 0, count); + } + + //---------------------------------------------------------------------------------------------- + public final void writeTo(final char... chs) { //只能是 0 - 127 的字符 + writeTo(chs, 0, chs.length); + } + + @Override + public final void writeBoolean(boolean value) { + writeTo(value ? CHARS_TUREVALUE : CHARS_FALSEVALUE); + } + + @Override + public final void writeByte(byte value) { + writeInt(value); + } + + @Override + public final void writeChar(char value) { + writeInt(value); + } + + @Override + public final void writeShort(short value) { + writeInt(value); + } + + @Override + public final void writeInt(int value) { + writeSmallString(String.valueOf(value)); + } + + @Override + public final void writeLong(long value) { + writeSmallString(String.valueOf(value)); + } + + @Override + public final void writeFloat(float value) { + writeSmallString(String.valueOf(value)); + } + + @Override + public final void writeDouble(double value) { + writeSmallString(String.valueOf(value)); + } + + @Override + public final void wirteClassName(String clazz) { } @Override @@ -237,52 +226,38 @@ public class JsonWriter implements Writer { writeTo('}'); } - @Override - public final void writeField(boolean comma, Attribute attribute) { - if (comma) writeTo(','); - writeTo('"'); - writeSmallString(attribute.field()); - writeTo('"'); - writeTo(':'); - } - @Override public final void writeNull() { writeTo('n', 'u', 'l', 'l'); } @Override - public void writeArrayB(int size) { + public final void writeArrayB(int size) { writeTo('['); } @Override - public void writeArrayMark() { + public final void writeArrayMark() { writeTo(','); } @Override - public void writeArrayE() { + public final void writeArrayE() { writeTo(']'); } @Override - public void writeMapB(int size) { + public final void writeMapB(int size) { writeTo('{'); } @Override - public void writeMapMark() { + public final void writeMapMark() { writeTo(':'); } @Override - public void writeMapE() { + public final void writeMapE() { writeTo('}'); } - - @Override - public void writeSmallString(String value) { - writeTo(false, value); - } } diff --git a/src/com/wentch/redkale/net/http/HttpContext.java b/src/com/wentch/redkale/net/http/HttpContext.java index 32d015ea0..3c5807013 100644 --- a/src/com/wentch/redkale/net/http/HttpContext.java +++ b/src/com/wentch/redkale/net/http/HttpContext.java @@ -60,6 +60,10 @@ public final class HttpContext extends Context { return responsePool; } + protected ObjectPool getBufferPool() { + return bufferPool; + } + public JsonConvert getJsonConvert() { return jsonFactory.getConvert(); } diff --git a/src/com/wentch/redkale/net/http/HttpResponse.java b/src/com/wentch/redkale/net/http/HttpResponse.java index b550e6269..616c5a1df 100644 --- a/src/com/wentch/redkale/net/http/HttpResponse.java +++ b/src/com/wentch/redkale/net/http/HttpResponse.java @@ -18,6 +18,7 @@ import java.nio.file.*; import java.text.*; import java.util.*; import java.util.concurrent.atomic.*; +import java.util.function.*; /** * @@ -147,6 +148,10 @@ public class HttpResponse extends Response { return v == null ? defValue : v; } + protected Supplier getByteBufferSupplier() { + return ((HttpContext) context).getBufferPool(); + } + @Override public HttpContext getContext() { return (HttpContext) context; @@ -165,17 +170,17 @@ public class HttpResponse extends Response { public void finishJson(Object obj) { this.contentType = "text/plain; charset=utf-8"; - finish(request.convert.convertTo(obj)); + finish(request.convert.convertTo(context.getCharset(), getByteBufferSupplier(), obj)); } public void finishJson(Type type, Object obj) { this.contentType = "text/plain; charset=utf-8"; - finish(request.convert.convertTo(type, obj)); + finish(request.convert.convertTo(context.getCharset(), getByteBufferSupplier(), type, obj)); } public void finishJson(Object... objs) { this.contentType = "text/plain; charset=utf-8"; - finish(request.convert.convertTo(objs)); + finish(request.convert.convertTo(context.getCharset(), getByteBufferSupplier(), objs)); } public void finish(String obj) { diff --git a/src/com/wentch/redkale/util/Utility.java b/src/com/wentch/redkale/util/Utility.java index 5ad319198..29d76c275 100644 --- a/src/com/wentch/redkale/util/Utility.java +++ b/src/com/wentch/redkale/util/Utility.java @@ -29,21 +29,26 @@ public final class Utility { private static final long strvaloffset; + private static final long sbvaloffset; + private static final javax.net.ssl.SSLContext DEFAULTSSL_CONTEXT; static { sun.misc.Unsafe usafe = null; - long fd = 0L; + long fd1 = 0L; + long fd2 = 0L; try { Field safeField = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); safeField.setAccessible(true); usafe = (sun.misc.Unsafe) safeField.get(null); - fd = usafe.objectFieldOffset(String.class.getDeclaredField("value")); + fd1 = usafe.objectFieldOffset(String.class.getDeclaredField("value")); + fd2 = usafe.objectFieldOffset(StringBuilder.class.getSuperclass().getDeclaredField("value")); } catch (Exception e) { throw new RuntimeException(e); //不可能会发生 } UNSAFE = usafe; - strvaloffset = fd; + strvaloffset = fd1; + sbvaloffset = fd2; try { DEFAULTSSL_CONTEXT = javax.net.ssl.SSLContext.getInstance("SSL"); @@ -304,6 +309,10 @@ public final class Utility { return value == null ? null : (char[]) UNSAFE.getObject(value, strvaloffset); } + public static char[] charArray(StringBuilder value) { + return value == null ? null : (char[]) UNSAFE.getObject(value, sbvaloffset); + } + public static ByteBuffer encodeUTF8(final ByteBuffer buffer, final char[] array) { return encodeUTF8(buffer, array, 0, array.length); }