diff --git a/src/org/redkale/convert/bson/BsonByteBufferReader.java b/src/org/redkale/convert/bson/BsonByteBufferReader.java new file mode 100644 index 000000000..5bfd623be --- /dev/null +++ b/src/org/redkale/convert/bson/BsonByteBufferReader.java @@ -0,0 +1,164 @@ +/* + * 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 org.redkale.convert.bson; + +import java.nio.*; +import org.redkale.convert.*; +import static org.redkale.convert.Reader.SIGN_NULL; +import org.redkale.util.*; + +/** + * + * @author zhangjx + */ +public final class BsonByteBufferReader extends BsonReader { + + private ByteBuffer[] buffers; + + private int currentIndex = 0; + + private ByteBuffer currentBuffer; + + protected BsonByteBufferReader(ByteBuffer... buffers) { + this.buffers = buffers; + this.currentBuffer = buffers[currentIndex]; + } + + @Override + protected boolean recycle() { + super.recycle(); // this.position 初始化值为-1 + this.currentIndex = 0; + this.currentBuffer = null; + this.buffers = null; + return false; + } + + @Override + protected byte currentByte() { + return currentBuffer.get(currentBuffer.position()); + } + + /** + * 判断下一个非空白字节是否为[ + * + * @return + */ + @Override + public int readArrayB() { + short bt = readShort(); + if (bt == Reader.SIGN_NULL) return bt; + short lt = readShort(); + return (bt & 0xffff) << 16 | (lt & 0xffff); + } +//------------------------------------------------------------ + + @Override + public boolean readBoolean() { + return readByte() == 1; + } + + @Override + public byte readByte() { + if (this.currentBuffer.hasRemaining()) { + this.position++; + return this.currentBuffer.get(); + } + for (;;) { + this.currentBuffer = this.buffers[++this.currentIndex]; + if (this.currentBuffer.hasRemaining()) { + this.position++; + return this.currentBuffer.get(); + } + } + } + + @Override + public char readChar() { + int remain = this.currentBuffer.remaining(); + if (remain >= 2) { + this.position += 2; + return this.currentBuffer.getChar(); + } + return (char) ((0xff00 & (readByte() << 8)) | (0xff & readByte())); + } + + @Override + public short readShort() { + int remain = this.currentBuffer.remaining(); + if (remain >= 2) { + this.position += 2; + return this.currentBuffer.getShort(); + } + return (short) ((0xff00 & (readByte() << 8)) | (0xff & readByte())); + } + + @Override + public int readInt() { + int remain = this.currentBuffer.remaining(); + if (remain >= 4) { + this.position += 4; + return this.currentBuffer.getInt(); + } + return ((readByte() & 0xff) << 24) | ((readByte() & 0xff) << 16) | ((readByte() & 0xff) << 8) | (readByte() & 0xff); + } + + @Override + public long readLong() { + int remain = this.currentBuffer.remaining(); + if (remain >= 8) { + this.position += 8; + return this.currentBuffer.getLong(); + } + return ((((long) readByte() & 0xff) << 56) + | (((long) readByte() & 0xff) << 48) + | (((long) readByte() & 0xff) << 40) + | (((long) readByte() & 0xff) << 32) + | (((long) readByte() & 0xff) << 24) + | (((long) readByte() & 0xff) << 16) + | (((long) readByte() & 0xff) << 8) + | (((long) readByte() & 0xff))); + } + + protected byte[] read(final int len) { + byte[] bs = new byte[len]; + read(bs, 0); + return bs; + } + + protected void read(final byte[] bs, final int pos) { + int remain = this.currentBuffer.remaining(); + if (remain < 1) { + this.currentBuffer = this.buffers[++this.currentIndex]; + read(bs, pos); + return; + } + int len = bs.length - pos; + if (remain >= len) { + this.position += len; + this.currentBuffer.get(bs, pos, len); + return; + } + this.currentBuffer.get(bs, pos, remain); + this.position += remain; + this.currentBuffer = this.buffers[++this.currentIndex]; + read(bs, pos + remain); + } + + @Override + public String readSmallString() { + int len = 0xff & readByte(); + if (len == 0) return ""; + return new String(read(len)); + } + + @Override + public String readString() { + int len = readInt(); + if (len == SIGN_NULL) return null; + if (len == 0) return ""; + return new String(Utility.decodeUTF8(read(len))); + } +} diff --git a/src/org/redkale/convert/bson/BsonConvert.java b/src/org/redkale/convert/bson/BsonConvert.java index f60a23b33..a618a7faf 100644 --- a/src/org/redkale/convert/bson/BsonConvert.java +++ b/src/org/redkale/convert/bson/BsonConvert.java @@ -12,22 +12,22 @@ import org.redkale.convert.*; import org.redkale.util.*; /** - * BSON协议格式: - * 1). 基本数据类型: 直接转换成byte[] - * 2). SmallString(无特殊字符且长度小于256的字符串): length(1 byte) + byte[](utf8); 通常用于类名、字段名、枚举。 - * 3). String: length(4 bytes) + byte[](utf8); - * 4). 数组: length(4 bytes) + byte[]... - * 5). Object: - * 1. realclass (SmallString) (如果指定格式化的class与实体对象的class不一致才会有该值) - * 2. 空字符串(SmallString) - * 3. SIGN_OBJECTB 标记位,值固定为0xBB (short) - * 4. 循环字段值: - * 4.1 SIGN_HASNEXT 标记位,值固定为1 (byte) - * 4.2 字段类型; 1-9为基本类型&字符串; 101-109为基本类型&字符串的数组; 127为Object - * 4.3 字段名 (SmallString) - * 4.4 字段的值Object - * 5. SIGN_NONEXT 标记位,值固定为0 (byte) - * 6. SIGN_OBJECTE 标记位,值固定为0xEE (short) + * BSON协议格式: + * 1). 基本数据类型: 直接转换成byte[] + * 2). SmallString(无特殊字符且长度小于256的字符串): length(1 byte) + byte[](utf8); 通常用于类名、字段名、枚举。 + * 3). String: length(4 bytes) + byte[](utf8); + * 4). 数组: length(4 bytes) + byte[]... + * 5). Object: + * 1. realclass (SmallString) (如果指定格式化的class与实体对象的class不一致才会有该值) + * 2. 空字符串(SmallString) + * 3. SIGN_OBJECTB 标记位,值固定为0xBB (short) + * 4. 循环字段值: + * 4.1 SIGN_HASNEXT 标记位,值固定为1 (byte) + * 4.2 字段类型; 1-9为基本类型&字符串; 101-109为基本类型&字符串的数组; 127为Object + * 4.3 字段名 (SmallString) + * 4.4 字段的值Object + * 5. SIGN_NONEXT 标记位,值固定为0 (byte) + * 6. SIGN_OBJECTE 标记位,值固定为0xEE (short) * * @see http://www.redkale.org * @author zhangjx @@ -80,6 +80,11 @@ public final class BsonConvert extends Convert { return rs; } + public T convertFrom(final Type type, final ByteBuffer... buffers) { + if (type == null || buffers.length < 1) return null; + return (T) factory.loadDecoder(type).convertFrom(new BsonByteBufferReader(buffers)); + } + public T convertFrom(final BsonReader in, final Type type) { if (type == null) return null; @SuppressWarnings("unchecked") diff --git a/src/org/redkale/convert/bson/BsonReader.java b/src/org/redkale/convert/bson/BsonReader.java index 6a736c79e..ad67f595f 100644 --- a/src/org/redkale/convert/bson/BsonReader.java +++ b/src/org/redkale/convert/bson/BsonReader.java @@ -159,24 +159,28 @@ public class BsonReader implements Reader { * */ @Override - public int readObjectB() { + public final int readObjectB() { short bt = readShort(); if (bt == Reader.SIGN_NULL) return bt; if (bt != SIGN_OBJECTB) { throw new ConvertException("a bson object must begin with " + (SIGN_OBJECTB) - + " (position = " + position + ") but '" + this.content[this.position] + "'"); + + " (position = " + position + ") but '" + currentByte() + "'"); } return bt; } @Override - public void readObjectE() { + public final void readObjectE() { if (readShort() != SIGN_OBJECTE) { throw new ConvertException("a bson object must end with " + (SIGN_OBJECTE) - + " (position = " + position + ") but '" + this.content[this.position] + "'"); + + " (position = " + position + ") but '" + currentByte() + "'"); } } + protected byte currentByte() { + return this.content[this.position]; + } + @Override public final int readMapB() { return readArrayB(); @@ -288,17 +292,17 @@ public class BsonReader implements Reader { } @Override - public float readFloat() { + public final float readFloat() { return Float.intBitsToFloat(readInt()); } @Override - public double readDouble() { + public final double readDouble() { return Double.longBitsToDouble(readLong()); } @Override - public String readClassName() { + public final String readClassName() { return readSmallString(); } @@ -307,7 +311,7 @@ public class BsonReader implements Reader { int len = 0xff & readByte(); if (len == 0) return ""; String value = new String(content, ++this.position, len); - this.position += len - 1; + this.position += len - 1; //上一行已经++this.position,所以此处要-1 return value; } @@ -317,7 +321,7 @@ public class BsonReader implements Reader { if (len == SIGN_NULL) return null; if (len == 0) return ""; String value = new String(Utility.decodeUTF8(content, ++this.position, len)); - this.position += len - 1; + this.position += len - 1;//上一行已经++this.position,所以此处要-1 return value; }