diff --git a/android-jdk6-redkale/src/com/wentch/redkale/convert/ConvertColumn.java b/android-jdk6-redkale/src/com/wentch/redkale/convert/ConvertColumn.java index a53828894..1a868f0c4 100644 --- a/android-jdk6-redkale/src/com/wentch/redkale/convert/ConvertColumn.java +++ b/android-jdk6-redkale/src/com/wentch/redkale/convert/ConvertColumn.java @@ -18,7 +18,7 @@ import static java.lang.annotation.RetentionPolicy.*; @Documented @Target({METHOD, FIELD}) @Retention(RUNTIME) -//@Repeatable(ConvertColumns.class) +@Repeatable(ConvertColumns.class) public @interface ConvertColumn { /** diff --git a/android-jdk6-redkale/src/com/wentch/redkale/convert/Factory.java b/android-jdk6-redkale/src/com/wentch/redkale/convert/Factory.java index 25ec6f9ba..c27cdfc75 100644 --- a/android-jdk6-redkale/src/com/wentch/redkale/convert/Factory.java +++ b/android-jdk6-redkale/src/com/wentch/redkale/convert/Factory.java @@ -128,8 +128,7 @@ public abstract class Factory { ConvertColumnEntry en = this.columnEntrys.get(field); if (en != null) return en; final ConvertType ct = this.getConvertType(); - ConvertColumn ref = field.getAnnotation(ConvertColumn.class); - if (ref != null) { + for (ConvertColumn ref : field.getAnnotationsByType(ConvertColumn.class)) { if (ref.type().contains(ct)) { ConvertColumnEntry entry = new ConvertColumnEntry(ref); if (skipAllIgnore) { diff --git a/android-jdk6-redkale/src/com/wentch/redkale/convert/ObjectDecoder.java b/android-jdk6-redkale/src/com/wentch/redkale/convert/ObjectDecoder.java index d62e7572f..80600ff71 100644 --- a/android-jdk6-redkale/src/com/wentch/redkale/convert/ObjectDecoder.java +++ b/android-jdk6-redkale/src/com/wentch/redkale/convert/ObjectDecoder.java @@ -32,6 +32,10 @@ public final class ObjectDecoder implements Decodeable implements Decodeable list = new HashSet(); try { - ConvertColumnEntry ref; - for (final Field field : clazz.getFields()) { - if (Modifier.isStatic(field.getModifiers())) continue; - ref = factory.findRef(field); - if (ref != null && ref.ignore()) continue; - Type t = ObjectEncoder.makeGenericType(field.getGenericType(), virGenericTypes, realGenericTypes); - list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, field, null, null), factory.loadDecoder(t))); + if (type == Object.class) return; + + Class clazz = null; + if (type instanceof ParameterizedType) { + final ParameterizedType pts = (ParameterizedType) type; + clazz = (Class) (pts).getRawType(); + } else if (!(type instanceof Class)) { + throw new ConvertException("[" + type + "] is no a class"); + } else { + clazz = (Class) type; } - final boolean reversible = factory.isReversible(); - for (final Method method : clazz.getMethods()) { - if (Modifier.isStatic(method.getModifiers())) continue; - if (Modifier.isAbstract(method.getModifiers())) continue; - if (method.isSynthetic()) continue; - if (method.getName().length() < 4) continue; - if (!method.getName().startsWith("set")) continue; - if (method.getParameterTypes().length != 1) continue; - if (method.getReturnType() != void.class) continue; - if (reversible) { - boolean is = method.getParameterTypes()[0] == boolean.class || method.getParameterTypes()[0] == Boolean.class; - try { - clazz.getMethod(method.getName().replaceFirst("set", is ? "is" : "get")); - } catch (Exception e) { - continue; - } + final Type[] virGenericTypes = this.typeClass.getTypeParameters(); + final Type[] realGenericTypes = (type instanceof ParameterizedType) ? ((ParameterizedType) type).getActualTypeArguments() : TYPEZERO; + this.creator = factory.loadCreator(clazz); + final Set list = new HashSet(); + try { + ConvertColumnEntry ref; + for (final Field field : clazz.getFields()) { + if (Modifier.isStatic(field.getModifiers())) continue; + ref = factory.findRef(field); + if (ref != null && ref.ignore()) continue; + Type t = ObjectEncoder.makeGenericType(field.getGenericType(), virGenericTypes, realGenericTypes); + list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, field, null, null), factory.loadDecoder(t))); } - ref = factory.findRef(method); - if (ref != null && ref.ignore()) continue; - Type t = ObjectEncoder.makeGenericType(method.getGenericParameterTypes()[0], virGenericTypes, realGenericTypes); - list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, null, method), factory.loadDecoder(t))); + final boolean reversible = factory.isReversible(); + for (final Method method : clazz.getMethods()) { + if (Modifier.isStatic(method.getModifiers())) continue; + if (Modifier.isAbstract(method.getModifiers())) continue; + if (method.isSynthetic()) continue; + if (method.getName().length() < 4) continue; + if (!method.getName().startsWith("set")) continue; + if (method.getParameterTypes().length != 1) continue; + if (method.getReturnType() != void.class) continue; + if (reversible) { + boolean is = method.getParameterTypes()[0] == boolean.class || method.getParameterTypes()[0] == Boolean.class; + try { + clazz.getMethod(method.getName().replaceFirst("set", is ? "is" : "get")); + } catch (Exception e) { + continue; + } + } + ref = factory.findRef(method); + if (ref != null && ref.ignore()) continue; + Type t = ObjectEncoder.makeGenericType(method.getGenericParameterTypes()[0], virGenericTypes, realGenericTypes); + list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, null, method), factory.loadDecoder(t))); + } + this.members = list.toArray(new DeMember[list.size()]); + Arrays.sort(this.members); + } catch (Exception ex) { + throw new ConvertException(ex); + } + } finally { + inited = true; + synchronized (lock) { + lock.notifyAll(); } - this.members = list.toArray(new DeMember[list.size()]); - Arrays.sort(this.members); - } catch (Exception ex) { - throw new ConvertException(ex); } } @@ -109,6 +120,15 @@ public final class ObjectDecoder implements Decodeable implements Encodeable implements Encodeable list = new HashSet(); - final Type[] virGenericTypes = this.typeClass.getTypeParameters(); - final Type[] realGenericTypes = (type instanceof ParameterizedType) ? ((ParameterizedType) type).getActualTypeArguments() : null; - if (realGenericTypes != null) { - // println(type + "," + Arrays.toString(virGenericTypes) + ", " + Arrays.toString(realGenericTypes)); - } try { - ConvertColumnEntry ref; - for (final Field field : clazz.getFields()) { - if (Modifier.isStatic(field.getModifiers())) continue; - ref = factory.findRef(field); - if (ref != null && ref.ignore()) continue; - Type t = makeGenericType(field.getGenericType(), virGenericTypes, realGenericTypes); - list.add(new EnMember(createAttribute(factory, clazz, field, null, null), factory.loadEncoder(t))); + if (type == Object.class) return; + //if (!(type instanceof Class)) throw new ConvertException("[" + type + "] is no a class"); + final Class clazz = this.typeClass; + final Set list = new HashSet(); + final Type[] virGenericTypes = this.typeClass.getTypeParameters(); + final Type[] realGenericTypes = (type instanceof ParameterizedType) ? ((ParameterizedType) type).getActualTypeArguments() : null; + if (realGenericTypes != null) { + // println(type + "," + Arrays.toString(virGenericTypes) + ", " + Arrays.toString(realGenericTypes)); } - final boolean reversible = factory.isReversible(); - for (final Method method : clazz.getMethods()) { - if (Modifier.isStatic(method.getModifiers())) continue; - if (Modifier.isAbstract(method.getModifiers())) continue; - if (method.isSynthetic()) continue; - if (method.getName().length() < 3) continue; - if (method.getName().equals("getClass")) continue; - if (!method.getName().startsWith("is") && !method.getName().startsWith("get")) continue; - if (method.getParameterTypes().length != 0) continue; - if (method.getReturnType() == void.class) continue; - if (reversible) { - boolean is = method.getName().startsWith("is"); - try { - clazz.getMethod(method.getName().replaceFirst(is ? "is" : "get", "set"), method.getReturnType()); - } catch (Exception e) { - continue; - } + try { + ConvertColumnEntry ref; + for (final Field field : clazz.getFields()) { + if (Modifier.isStatic(field.getModifiers())) continue; + ref = factory.findRef(field); + if (ref != null && ref.ignore()) continue; + Type t = makeGenericType(field.getGenericType(), virGenericTypes, realGenericTypes); + list.add(new EnMember(createAttribute(factory, clazz, field, null, null), factory.loadEncoder(t))); } - ref = factory.findRef(method); - if (ref != null && ref.ignore()) continue; - Type t = makeGenericType(method.getGenericReturnType(), virGenericTypes, realGenericTypes); - list.add(new EnMember(createAttribute(factory, clazz, null, method, null), factory.loadEncoder(t))); - } - this.members = list.toArray(new EnMember[list.size()]); - Arrays.sort(this.members); + final boolean reversible = factory.isReversible(); + for (final Method method : clazz.getMethods()) { + if (Modifier.isStatic(method.getModifiers())) continue; + if (Modifier.isAbstract(method.getModifiers())) continue; + if (method.isSynthetic()) continue; + if (method.getName().length() < 3) continue; + if (method.getName().equals("getClass")) continue; + if (!method.getName().startsWith("is") && !method.getName().startsWith("get")) continue; + if (method.getParameterTypes().length != 0) continue; + if (method.getReturnType() == void.class) continue; + if (reversible) { + boolean is = method.getName().startsWith("is"); + try { + clazz.getMethod(method.getName().replaceFirst(is ? "is" : "get", "set"), method.getReturnType()); + } catch (Exception e) { + continue; + } + } + ref = factory.findRef(method); + if (ref != null && ref.ignore()) continue; + Type t = makeGenericType(method.getGenericReturnType(), virGenericTypes, realGenericTypes); + list.add(new EnMember(createAttribute(factory, clazz, null, method, null), factory.loadEncoder(t))); + } + this.members = list.toArray(new EnMember[list.size()]); + Arrays.sort(this.members); - } catch (Exception ex) { - throw new ConvertException(ex); + } catch (Exception ex) { + throw new ConvertException(ex); + } + } finally { + inited = true; + synchronized (lock) { + lock.notifyAll(); + } } } @@ -188,6 +199,15 @@ public final class ObjectEncoder implements Encodeable supplier; + + private ByteBuffer[] buffers; + + private int index; + + protected BsonByteBufferWriter(Supplier supplier) { + super((byte[]) null); + this.supplier = supplier; + } + + @Override + public ByteBuffer[] toBuffers() { + if (buffers == null) return new ByteBuffer[0]; + for (int i = index; i < this.buffers.length; i++) { + ByteBuffer buf = this.buffers[i]; + if (buf.position() != 0) buf.flip(); + } + return this.buffers; + } + + @Override + public byte[] toArray() { + if (buffers == null) return new byte[0]; + int pos = 0; + byte[] bytes = new byte[this.count]; + for (ByteBuffer buf : toBuffers()) { + int r = buf.remaining(); + buf.get(bytes, pos, r); + buf.flip(); + pos += r; + } + return bytes; + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "[count=" + this.count + "]"; + } + + @Override + public BsonByteBufferWriter setTiny(boolean tiny) { + this.tiny = tiny; + return this; + } + + @Override + protected int 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++; + } + int len = buffer.remaining(); + int size = 0; + 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(); + size++; + } + return size; + } + + @Override + public void writeTo(final byte[] chs, final int start, final int len) { + if (expand(len) == 0) { + this.buffers[index].put(chs, start, len); + } else { + ByteBuffer buffer = this.buffers[index]; + final int end = start + len; + int remain = len; //还剩多少没有写 + while (remain > 0) { + final int br = buffer.remaining(); + if (remain > br) { //一个buffer写不完 + buffer.put(chs, end - remain, br); + buffer = nextByteBuffer(); + remain -= br; + } else { + buffer.put(chs, end - remain, remain); + remain = 0; + } + } + } + this.count += len; + } + + private ByteBuffer nextByteBuffer() { + this.buffers[this.index].flip(); + return this.buffers[++this.index]; + } + + @Override + public void writeTo(final byte ch) { + expand(1); + this.buffers[index].put(ch); + count++; + } + + @Override + protected boolean recycle() { + this.index = 0; + this.buffers = null; + return false; + } +} diff --git a/android-jdk6-redkale/src/com/wentch/redkale/convert/bson/BsonConvert.java b/android-jdk6-redkale/src/com/wentch/redkale/convert/bson/BsonConvert.java index 30f0bab2d..3312c0b31 100644 --- a/android-jdk6-redkale/src/com/wentch/redkale/convert/bson/BsonConvert.java +++ b/android-jdk6-redkale/src/com/wentch/redkale/convert/bson/BsonConvert.java @@ -43,10 +43,12 @@ public final class BsonConvert extends Convert { this.tiny = tiny; } + public BsonByteBufferWriter pollBsonWriter(final Supplier supplier) { + return new BsonByteBufferWriter(supplier).setTiny(tiny); + } + public BsonWriter pollBsonWriter() { - final BsonWriter out = writerPool.get(); - out.setTiny(tiny); - return out; + return writerPool.get().setTiny(tiny); } public void offerBsonWriter(BsonWriter out) { @@ -85,8 +87,7 @@ public final class BsonConvert extends Convert { public byte[] convertTo(final Type type, Object value) { if (type == null) return null; - final BsonWriter out = writerPool.get(); - out.setTiny(tiny); + final BsonWriter out = writerPool.get().setTiny(tiny); factory.loadEncoder(type).convertTo(out, value); byte[] result = out.toArray(); writerPool.offer(out); @@ -98,6 +99,28 @@ public final class BsonConvert extends Convert { factory.loadEncoder(type).convertTo(out, value); } + public ByteBuffer[] convertTo(final Supplier supplier, final Type type, Object value) { + if (supplier == null || type == null) return null; + BsonByteBufferWriter out = new BsonByteBufferWriter(supplier); + if (value == null) { + out.writeNull(); + } else { + factory.loadEncoder(type).convertTo(out, value); + } + return out.toBuffers(); + } + + public ByteBuffer[] convertTo(final Supplier supplier, Object value) { + if (supplier == null) return null; + BsonByteBufferWriter out = new BsonByteBufferWriter(supplier); + if (value == null) { + out.writeNull(); + } else { + factory.loadEncoder(value.getClass()).convertTo(out, value); + } + return out.toBuffers(); + } + public void convertTo(final BsonWriter out, Object value) { if (value == null) { out.writeNull(); @@ -108,8 +131,7 @@ public final class BsonConvert extends Convert { public byte[] convertTo(Object value) { if (value == null) { - final BsonWriter out = writerPool.get(); - out.setTiny(tiny); + final BsonWriter out = writerPool.get().setTiny(tiny); out.writeNull(); byte[] result = out.toArray(); writerPool.offer(out); @@ -118,25 +140,15 @@ public final class BsonConvert extends Convert { return convertTo(value.getClass(), value); } - public ByteBuffer convertToBuffer(final Type type, Object value) { + public BsonWriter convertToWriter(final Type type, Object value) { if (type == null) return null; - final BsonWriter out = writerPool.get(); - out.setTiny(tiny); + final BsonWriter out = writerPool.get().setTiny(tiny); factory.loadEncoder(type).convertTo(out, value); - ByteBuffer result = out.toBuffer(); - writerPool.offer(out); - return result; + return out; } - public ByteBuffer convertToBuffer(Object value) { - if (value == null) { - final BsonWriter out = writerPool.get(); - out.setTiny(tiny); - out.writeNull(); - ByteBuffer result = out.toBuffer(); - writerPool.offer(out); - return result; - } - return convertToBuffer(value.getClass(), value); + public BsonWriter convertToWriter(Object value) { + if (value == null) return null; + return convertToWriter(value.getClass(), value); } } diff --git a/android-jdk6-redkale/src/com/wentch/redkale/convert/bson/BsonReader.java b/android-jdk6-redkale/src/com/wentch/redkale/convert/bson/BsonReader.java index 45dee764b..69e2a2b79 100644 --- a/android-jdk6-redkale/src/com/wentch/redkale/convert/bson/BsonReader.java +++ b/android-jdk6-redkale/src/com/wentch/redkale/convert/bson/BsonReader.java @@ -62,13 +62,21 @@ public final class BsonReader implements Reader { } public final void setBytes(byte[] bytes) { - setBytes(bytes, 0, bytes.length); + if (bytes == null) { + this.position = 0; + } else { + setBytes(bytes, 0, bytes.length); + } } public final void setBytes(byte[] bytes, int start, int len) { - this.content = bytes; - this.position = start - 1; - //this.limit = start + len - 1; + if (bytes == null) { + this.position = 0; + } else { + this.content = bytes; + this.position = start - 1; + //this.limit = start + len - 1; + } } protected boolean recycle() { diff --git a/android-jdk6-redkale/src/com/wentch/redkale/convert/bson/BsonWriter.java b/android-jdk6-redkale/src/com/wentch/redkale/convert/bson/BsonWriter.java index 17a23a40c..4b185d5a6 100644 --- a/android-jdk6-redkale/src/com/wentch/redkale/convert/bson/BsonWriter.java +++ b/android-jdk6-redkale/src/com/wentch/redkale/convert/bson/BsonWriter.java @@ -13,14 +13,14 @@ import java.nio.*; * * @author zhangjx */ -public final class BsonWriter implements Writer { +public class BsonWriter implements Writer { private static final int defaultSize = Integer.getInteger("convert.bson.writer.buffer.defsize", 1024); - protected int count; - private byte[] content; + protected int count; + protected boolean tiny; public static ObjectPool createPool(int max) { @@ -46,8 +46,12 @@ public final class BsonWriter implements Writer { return newdata; } - public ByteBuffer toBuffer() { - return ByteBuffer.wrap(content, 0, count); + public ByteBuffer[] toBuffers() { + return new ByteBuffer[]{ByteBuffer.wrap(content, 0, count)}; + } + + protected BsonWriter(byte[] bs) { + this.content = bs; } public BsonWriter() { @@ -55,60 +59,34 @@ public final class BsonWriter implements Writer { } public BsonWriter(int size) { - this.content = new byte[size > 32 ? size : 32]; + this.content = new byte[size > 128 ? size : 128]; } @Override - public boolean isTiny() { + public final boolean isTiny() { return tiny; } - public void setTiny(boolean tiny) { + public BsonWriter setTiny(boolean tiny) { this.tiny = tiny; + return this; } //----------------------------------------------------------------------- //----------------------------------------------------------------------- /** - * 返回指定至少指定长度的缓冲区 + * 扩充指定长度的缓冲区 * * @param len * @return */ - public byte[] expand(int len) { + protected int expand(int len) { int newcount = count + len; - if (newcount <= content.length) return content; + if (newcount <= content.length) return 0; byte[] newdata = new byte[Math.max(content.length * 3 / 2, newcount)]; System.arraycopy(content, 0, newdata, 0, count); this.content = newdata; - return newdata; - } - - /** - * 往指定的位置写入字节 - * - * @param position - * @param chs - */ - public void rewriteTo(int position, byte... chs) { - System.arraycopy(chs, 0, content, position, chs.length); - } - - public void rewriteTo(int position, short value) { - rewriteTo(position, (byte) (value >> 8), (byte) value); - } - - public void rewriteTo(int position, char value) { - rewriteTo(position, (byte) ((value & 0xFF00) >> 8), (byte) (value & 0xFF)); - } - - public void rewriteTo(int position, int value) { - rewriteTo(position, (byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) value); - } - - public void rewriteTo(int position, long value) { - rewriteTo(position, (byte) (value >> 56), (byte) (value >> 48), (byte) (value >> 40), (byte) (value >> 32), - (byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) value); + return 0; } public void writeTo(final byte ch) { @@ -116,15 +94,11 @@ public final class BsonWriter implements Writer { content[count++] = ch; } - public void writeTo(final byte... chs) { - int len = chs.length; - expand(len); - System.arraycopy(chs, 0, content, count, len); - count += len; + public final void writeTo(final byte... chs) { + writeTo(chs, 0, chs.length); } - public void writeTo(final byte[] chs, final int start, final int end) { - int len = end - start; + public void writeTo(final byte[] chs, final int start, final int len) { expand(len); System.arraycopy(chs, start, content, count, len); count += len; @@ -138,68 +112,59 @@ public final class BsonWriter implements Writer { return true; } - //------------------------------------------------------------------------ - public int position() { - return this.count; + @Override + public String toString() { + return this.getClass().getSimpleName() + "[count=" + this.count + "]"; } + //------------------------------------------------------------------------ public final int count() { return this.count; } - public final void count(int count) { - if (count >= 0) this.count = count; - } - - //----------------------------------------------------------------------- @Override - public String toString() { - return new String(content, 0, count); - } - - @Override - public void writeBoolean(boolean value) { + public final void writeBoolean(boolean value) { writeTo(value ? (byte) 1 : (byte) 0); } @Override - public void writeByte(byte value) { + public final void writeByte(byte value) { writeTo(value); } @Override - public void writeChar(final char value) { + public final void writeChar(final char value) { writeTo((byte) ((value & 0xFF00) >> 8), (byte) (value & 0xFF)); } @Override - public void writeShort(short value) { + public final void writeShort(short value) { writeTo((byte) (value >> 8), (byte) value); } @Override - public void writeInt(int value) { + public final void writeInt(int value) { writeTo((byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) value); } @Override - public void writeLong(long value) { + public final void writeLong(long value) { writeTo((byte) (value >> 56), (byte) (value >> 48), (byte) (value >> 40), (byte) (value >> 32), (byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) value); } @Override - public void writeFloat(float value) { + public final void writeFloat(float value) { writeInt(Float.floatToIntBits(value)); } @Override - public void writeDouble(double value) { + public final void writeDouble(double value) { writeLong(Double.doubleToLongBits(value)); } @Override - public void wirteClassName(String clazz) { + public final void wirteClassName(String clazz) { writeSmallString(clazz == null ? "" : clazz); } @@ -267,7 +232,7 @@ public final class BsonWriter implements Writer { * @param value */ @Override - public void writeSmallString(String value) { + public final void writeSmallString(String value) { if (value.isEmpty()) { writeTo((byte) 0); return; @@ -284,7 +249,7 @@ public final class BsonWriter implements Writer { } @Override - public void writeString(String value) { + public final void writeString(String value) { if (value == null) { writeInt(Reader.SIGN_NULL); return; @@ -303,16 +268,16 @@ public final class BsonWriter implements Writer { } @Override - public void writeArrayB(int size) { + public final void writeArrayB(int size) { writeInt(size); } @Override - public void writeArrayMark() { + public final void writeArrayMark() { } @Override - public void writeArrayE() { + public final void writeArrayE() { } @Override @@ -321,11 +286,11 @@ public final class BsonWriter implements Writer { } @Override - public void writeMapMark() { + public final void writeMapMark() { } @Override - public void writeMapE() { + public final void writeMapE() { } } diff --git a/android-jdk6-redkale/src/com/wentch/redkale/convert/json/JsonByteBufferWriter.java b/android-jdk6-redkale/src/com/wentch/redkale/convert/json/JsonByteBufferWriter.java new file mode 100644 index 000000000..f135d9525 --- /dev/null +++ b/android-jdk6-redkale/src/com/wentch/redkale/convert/json/JsonByteBufferWriter.java @@ -0,0 +1,348 @@ +/* + * 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 com.wentch.redkale.util.Supplier; +import java.nio.*; +import java.nio.charset.*; +import java.util.*; + +/** + * + * @author zhangjx + */ +public final 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; + + protected JsonByteBufferWriter(Supplier supplier) { + this(null, supplier); + } + + protected JsonByteBufferWriter(Charset charset, Supplier supplier) { + this.charset = UTF8.equals(charset) ? null : charset; + this.supplier = supplier; + } + + @Override + public JsonByteBufferWriter setTiny(boolean tiny) { + this.tiny = tiny; + return this; + } + + @Override + protected boolean recycle() { + this.index = 0; + this.buffers = null; + return false; + } + + @Override + public ByteBuffer[] toBuffers() { + if (buffers == null) return new ByteBuffer[0]; + for (int i = index; i < this.buffers.length; i++) { + ByteBuffer buf = this.buffers[i]; + if (buf.position() != 0) buf.flip(); + } + return this.buffers; + } + + @Override + public int count() { + if (this.buffers == null) return 0; + int len = 0; + for (ByteBuffer buffer : buffers) { + len += buffer.remaining(); + } + return len; + } + + private int 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++; + } + int len = buffer.remaining(); + int size = 0; + 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(); + size++; + } + return size; + } + + @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(-1, false, chs, start, len); + } + + private void writeTo(int expandsize, 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(); + } + if (expandsize < 0) expandsize = expand(byteLength); + if (expandsize == 0) { // 只需要一个buffer + final ByteBuffer buffer = this.buffers[index]; + if (quote) buffer.put((byte) '"'); + + if (charset == null) { //UTF-8 + final int limit = start + len; + for (int i = start; i < limit; i++) { + char c = chs[i]; + if (c < 0x80) { + buffer.put((byte) c); + } else if (c < 0x800) { + buffer.put((byte) (0xc0 | (c >> 6))); + buffer.put((byte) (0x80 | (c & 0x3f))); + } else { + buffer.put((byte) (0xe0 | ((c >> 12)))); + buffer.put((byte) (0x80 | ((c >> 6) & 0x3f))); + buffer.put((byte) (0x80 | (c & 0x3f))); + } + } + } else { + buffer.put(bb); + } + + if (quote) buffer.put((byte) '"'); + return; + } + 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()) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(bb.get()); + } + } + 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; + } + + private static int encodeEscapeUTF8Length(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]; + switch (c) { + case '\n': size += 2; + break; + case '\r': size += 2; + break; + case '\t': size += 2; + break; + case '\\': size += 2; + break; + case '"': size += 2; + break; + default: + size += (c < 0x80 ? 1 : (c < 0x800 ? 2 : 3)); + break; + } + } + 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(-1, 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(-1, true, chs, 0, len); + return; + } + int expandsize = -1; + if (this.charset == null) { //UTF-8 + final int byteLength = 2 + encodeEscapeUTF8Length(chs, 0, chs.length); + expandsize = expand(byteLength); + if (expandsize == 0) { // 只需要一个buffer + final ByteBuffer buffer = this.buffers[index]; + buffer.put((byte) '"'); + for (char c : chs) { + switch (c) { + case '\n': buffer.put((byte) '\\').put((byte) 'n'); + break; + case '\r': buffer.put((byte) '\\').put((byte) 'r'); + break; + case '\t': buffer.put((byte) '\\').put((byte) 't'); + break; + case '\\': buffer.put((byte) '\\').put((byte) '\\'); + break; + case '"': buffer.put((byte) '\\').put((byte) '"'); + break; + default: + if (c < 0x80) { + buffer.put((byte) c); + } else if (c < 0x800) { + buffer.put((byte) (0xc0 | (c >> 6))); + buffer.put((byte) (0x80 | (c & 0x3f))); + } else { + buffer.put((byte) (0xe0 | ((c >> 12)))); + buffer.put((byte) (0x80 | ((c >> 6) & 0x3f))); + buffer.put((byte) (0x80 | (c & 0x3f))); + } + break; + } + } + buffer.put((byte) '"'); + return; + } + } + StringBuilder sb = new StringBuilder(len); + 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(expandsize, 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/android-jdk6-redkale/src/com/wentch/redkale/convert/json/JsonConvert.java b/android-jdk6-redkale/src/com/wentch/redkale/convert/json/JsonConvert.java index 6f5e79597..6201938d5 100644 --- a/android-jdk6-redkale/src/com/wentch/redkale/convert/json/JsonConvert.java +++ b/android-jdk6-redkale/src/com/wentch/redkale/convert/json/JsonConvert.java @@ -8,6 +8,8 @@ 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.*; /** * @@ -30,6 +32,22 @@ public final class JsonConvert extends Convert { this.tiny = tiny; } + public JsonByteBufferWriter pollJsonWriter(final Supplier supplier) { + return new JsonByteBufferWriter(supplier).setTiny(tiny); + } + + public JsonByteBufferWriter pollJsonWriter(final Charset charset, final Supplier supplier) { + return new JsonByteBufferWriter(charset, supplier).setTiny(tiny); + } + + public JsonWriter pollJsonWriter() { + return writerPool.get().setTiny(tiny); + } + + public void offerJsonWriter(JsonWriter out) { + if (out != null) writerPool.offer(out); + } + @Override public JsonFactory getFactory() { return (JsonFactory) factory; @@ -57,8 +75,7 @@ public final class JsonConvert extends Convert { public String convertTo(final Type type, Object value) { if (type == null) return null; if (value == null) return "null"; - final JsonWriter out = writerPool.get(); - out.setTiny(tiny); + final JsonWriter out = writerPool.get().setTiny(tiny); factory.loadEncoder(type).convertTo(out, value); String result = out.toString(); writerPool.offer(out); @@ -70,19 +87,50 @@ public final class JsonConvert extends Convert { return convertTo(value.getClass(), value); } - public byte[] convertToUTF8Bytes(Object value) { - if (value == null) return new byte[]{110, 117, 108, 108}; - return convertToUTF8Bytes(value.getClass(), value); + public void convertTo(final JsonWriter out, final Type type, Object value) { + if (type == null) return; + if (value == null) { + out.writeNull(); + } else { + factory.loadEncoder(type).convertTo(out, value); + } } - public byte[] convertToUTF8Bytes(final Type type, Object value) { - if (type == null) return null; - if (value == null) return new byte[]{110, 117, 108, 108}; - final JsonWriter out = writerPool.get(); - out.setTiny(tiny); - factory.loadEncoder(type).convertTo(out, value); - byte[] result = out.toUTF8Bytes(); - writerPool.offer(out); - return result; + public void convertTo(final JsonWriter out, Object value) { + if (value == null) { + out.writeNull(); + } else { + factory.loadEncoder(value.getClass()).convertTo(out, value); + } + } + + 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(); } } diff --git a/android-jdk6-redkale/src/com/wentch/redkale/convert/json/JsonWriter.java b/android-jdk6-redkale/src/com/wentch/redkale/convert/json/JsonWriter.java index 34f6481a5..111d3484b 100644 --- a/android-jdk6-redkale/src/com/wentch/redkale/convert/json/JsonWriter.java +++ b/android-jdk6-redkale/src/com/wentch/redkale/convert/json/JsonWriter.java @@ -7,6 +7,7 @@ package com.wentch.redkale.convert.json; import com.wentch.redkale.convert.*; import com.wentch.redkale.util.*; +import java.nio.*; /** * @@ -14,7 +15,7 @@ import com.wentch.redkale.util.*; * * @author zhangjx */ -public final class JsonWriter implements Writer { +public class JsonWriter implements Writer { private static final char[] CHARS_TUREVALUE = "true".toCharArray(); @@ -22,7 +23,7 @@ public final 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; @@ -57,8 +58,9 @@ public final class JsonWriter implements Writer { return tiny; } - public void setTiny(boolean tiny) { + public JsonWriter setTiny(boolean tiny) { this.tiny = tiny; + return this; } //----------------------------------------------------------------------- @@ -69,7 +71,7 @@ public final 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)]; @@ -78,20 +80,12 @@ public final 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,88 +114,14 @@ public final class JsonWriter implements Writer { return true; } - public char[] toArray() { - if (count == content.length) return content; - char[] newdata = new char[count]; - System.arraycopy(content, 0, newdata, 0, count); - return newdata; + public ByteBuffer[] toBuffers() { + return new ByteBuffer[]{ByteBuffer.wrap(Utility.encodeUTF8(content, 0, count))}; } - public byte[] toUTF8Bytes() { - 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) { @@ -235,7 +155,69 @@ public final class JsonWriter implements Writer { } @Override - public void wirteClassName(String clazz) { + 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 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 @@ -248,52 +230,38 @@ public final 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/android-jdk6-redkale/src/com/wentch/redkale/net/client/WebSocketClient.java b/android-jdk6-redkale/src/com/wentch/redkale/net/client/WebSocketClient.java index 5b82c0033..a567666cb 100644 --- a/android-jdk6-redkale/src/com/wentch/redkale/net/client/WebSocketClient.java +++ b/android-jdk6-redkale/src/com/wentch/redkale/net/client/WebSocketClient.java @@ -18,6 +18,8 @@ import javax.net.ssl.*; */ public class WebSocketClient { + protected final boolean ssl; + protected final URI uri; protected final Map headers = new HashMap(); @@ -32,6 +34,7 @@ public class WebSocketClient { private WebSocketClient(URI uri, Map headers0) { this.uri = uri; + this.ssl = "wss".equalsIgnoreCase(uri.getScheme()); if (headers0 != null) this.headers.putAll(headers0); } @@ -65,26 +68,28 @@ public class WebSocketClient { public int getPort() { int port = uri.getPort(); if (port > 0) return port; - return "wss".equalsIgnoreCase(uri.getScheme()) ? 443 : 80; + return ssl ? 443 : 80; } public void connect() throws IOException { - if ("wss".equalsIgnoreCase(uri.getScheme())) { + if (ssl) { if (proxy == null) { this.socket = (sslContext == null ? Utility.getDefaultSSLContext() : sslContext).getSocketFactory().createSocket(uri.getHost(), getPort()); } else { Socket s = new Socket(proxy); + this.socket.setSoTimeout(3000); s.connect(new InetSocketAddress(uri.getHost(), getPort())); this.socket = (sslContext == null ? Utility.getDefaultSSLContext() : sslContext).getSocketFactory().createSocket(s, uri.getHost(), getPort(), true); } } else { this.socket = proxy == null ? new Socket() : new Socket(proxy); + this.socket.setSoTimeout(3000); this.socket.connect(new InetSocketAddress(uri.getHost(), getPort())); } } public static void main(String[] args) throws Exception { - URI uri = new URI("ws://10.28.2.207/pipes/ws/listen?test=aa"); + URI uri = new URI("ws://10.28.2.207:5050/pipes/ws/listen?test=aa"); WebSocketClient client = WebSocketClient.create(uri); client.connect(); System.out.println(); diff --git a/android-jdk6-redkale/src/com/wentch/redkale/util/Utility.java b/android-jdk6-redkale/src/com/wentch/redkale/util/Utility.java index 7f0c1e828..3ade605d7 100644 --- a/android-jdk6-redkale/src/com/wentch/redkale/util/Utility.java +++ b/android-jdk6-redkale/src/com/wentch/redkale/util/Utility.java @@ -255,6 +255,13 @@ public final class Utility { return value == null ? null : value.toCharArray(); } + public static char[] charArray(StringBuilder value) { + if (value == null) return null; + char[] chs = new char[value.length()]; + value.getChars(0, value.length(), chs, 0); + return chs; + } + public static ByteBuffer encodeUTF8(final ByteBuffer buffer, final char[] array) { return encodeUTF8(buffer, array, 0, array.length); } @@ -327,7 +334,7 @@ public final class Utility { } //----------------------------------------------------------------------------- - public static javax.net.ssl.SSLContext getDefaultSSLContext(){ + public static javax.net.ssl.SSLContext getDefaultSSLContext() { return DEFAULTSSL_CONTEXT; }