diff --git a/java/src/main/java/org/msgpack/Packer.java b/java/src/main/java/org/msgpack/Packer.java index 8349a308..8412f040 100644 --- a/java/src/main/java/org/msgpack/Packer.java +++ b/java/src/main/java/org/msgpack/Packer.java @@ -331,6 +331,23 @@ public class Packer { return packRawBody(b, off, length); } + public Packer packByteBuffer(ByteBuffer bb) throws IOException { + byte[] bytes = byteBufferToByteArray(bb); + return packByteArray(bytes); + } + + private static byte[] byteBufferToByteArray(ByteBuffer b) { + if (b.hasArray() && b.position() == 0 && b.arrayOffset() == 0 + && b.remaining() == b.capacity()) { + return b.array(); + } else { + int len = b.remaining(); + byte[] ret = new byte[len]; + System.arraycopy(b.array(), b.arrayOffset() + b.position(), ret, 0, len); + return ret; + } + } + public Packer packString(String s) throws IOException { byte[] b = ((String)s).getBytes("UTF-8"); packRaw(b.length); @@ -404,6 +421,11 @@ public class Packer { return packBigInteger(o); } + public Packer pack(ByteBuffer o) throws IOException { + if (o == null) { return packNil(); } + return packByteBuffer(o); + } + public Packer pack(Float o) throws IOException { if(o == null) { return packNil(); } return packFloat(o); diff --git a/java/src/main/java/org/msgpack/Unpacker.java b/java/src/main/java/org/msgpack/Unpacker.java index d07de1ec..04d44998 100644 --- a/java/src/main/java/org/msgpack/Unpacker.java +++ b/java/src/main/java/org/msgpack/Unpacker.java @@ -547,6 +547,11 @@ public class Unpacker implements Iterable { return impl.unpackByteArray(); } + public ByteBuffer unpackByteBuffer() throws IOException { + byte[] bytes = impl.unpackByteArray(); + return ByteBuffer.wrap(bytes); + } + /** * Gets one {@code String} value from the buffer. * This method calls {@link fill()} method if needed. diff --git a/java/src/main/java/org/msgpack/template/ByteBufferTemplate.java b/java/src/main/java/org/msgpack/template/ByteBufferTemplate.java new file mode 100644 index 00000000..82af4bbd --- /dev/null +++ b/java/src/main/java/org/msgpack/template/ByteBufferTemplate.java @@ -0,0 +1,39 @@ +package org.msgpack.template; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import org.msgpack.CustomMessage; +import org.msgpack.MessagePackObject; +import org.msgpack.MessageTypeException; +import org.msgpack.Packer; +import org.msgpack.Template; +import org.msgpack.Unpacker; + +public class ByteBufferTemplate implements Template { + private ByteBufferTemplate() { + } + + public void pack(Packer pk, Object target) throws IOException { + pk.packByteBuffer((ByteBuffer)target); + } + + public Object unpack(Unpacker pac) throws IOException, MessageTypeException { + return pac.unpackByteBuffer(); + } + + public Object convert(MessagePackObject from) throws MessageTypeException { + byte[] b = from.asByteArray(); + return ByteBuffer.wrap(b); + } + + static public ByteBufferTemplate getInstance() { + return instance; + } + + static final ByteBufferTemplate instance = new ByteBufferTemplate(); + + static { + CustomMessage.register(ByteBuffer.class, instance); + } +} diff --git a/java/src/main/java/org/msgpack/util/codegen/DynamicCodeGenBase.java b/java/src/main/java/org/msgpack/util/codegen/DynamicCodeGenBase.java index 2d2711aa..d18bb994 100644 --- a/java/src/main/java/org/msgpack/util/codegen/DynamicCodeGenBase.java +++ b/java/src/main/java/org/msgpack/util/codegen/DynamicCodeGenBase.java @@ -24,6 +24,7 @@ import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.math.BigInteger; +import java.nio.ByteBuffer; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; @@ -52,6 +53,7 @@ import org.msgpack.Unpacker; import org.msgpack.annotation.MessagePackDelegate; import org.msgpack.annotation.MessagePackMessage; import org.msgpack.annotation.MessagePackOrdinalEnum; +import org.msgpack.template.ByteBufferTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -317,6 +319,8 @@ public class DynamicCodeGenBase implements Constants { return Templates.tString(); } else if (c.equals(BigInteger.class)) { return Templates.tBigInteger(); + } else if (c.equals(ByteBuffer.class)) {// FIXME + return ByteBufferTemplate.getInstance(); } else if (CustomConverter.isRegistered(c)) {// FIXME return (Template) CustomConverter.get(c); } else if (CustomMessage.isAnnotated(c, MessagePackMessage.class)) { diff --git a/java/src/test/java/org/msgpack/template/TestPackConvert.java b/java/src/test/java/org/msgpack/template/TestPackConvert.java index 01063a51..50fa7a50 100644 --- a/java/src/test/java/org/msgpack/template/TestPackConvert.java +++ b/java/src/test/java/org/msgpack/template/TestPackConvert.java @@ -2,6 +2,7 @@ package org.msgpack.template; import java.io.ByteArrayOutputStream; import java.math.BigInteger; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -279,6 +280,73 @@ public class TestPackConvert extends TestCase { assertEquals(src, dst); } + @Test + public void testByteBuffer() throws Exception { + _testByteBuffer(ByteBuffer.wrap(("".getBytes()))); + _testByteBuffer(ByteBuffer.wrap(("a".getBytes()))); + _testByteBuffer(ByteBuffer.wrap(("ab".getBytes()))); + _testByteBuffer(ByteBuffer.wrap(("abc".getBytes()))); + + // small size string + for (int i = 0; i < 100; i++) { + StringBuilder sb = new StringBuilder(); + int len = (int) Math.random() % 31 + 1; + for (int j = 0; j < len; j++) { + sb.append('a' + ((int) Math.random()) & 26); + } + _testByteBuffer(ByteBuffer.wrap(sb.toString().getBytes())); + } + + // medium size string + for (int i = 0; i < 100; i++) { + StringBuilder sb = new StringBuilder(); + int len = (int) Math.random() % 100 + (1 << 15); + for (int j = 0; j < len; j++) { + sb.append('a' + ((int) Math.random()) & 26); + } + _testByteBuffer(ByteBuffer.wrap(sb.toString().getBytes())); + } + + // large size string + for (int i = 0; i < 10; i++) { + StringBuilder sb = new StringBuilder(); + int len = (int) Math.random() % 100 + (1 << 31); + for (int j = 0; j < len; j++) { + sb.append('a' + ((int) Math.random()) & 26); + } + _testByteBuffer(ByteBuffer.wrap(sb.toString().getBytes())); + } + } + + static void _testByteBuffer(ByteBuffer src) throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + new Packer(out).pack(src); + MessagePackObject obj = Util.unpackOne(out.toByteArray()); + Template tmpl = ByteBufferTemplate.getInstance(); + ByteBuffer dst = (ByteBuffer) tmpl.convert(obj); + assertEquals(src, dst); + } + + @Test + public void testNullByteBuffer() throws Exception { + ByteBuffer src = null; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + new Packer(out).pack(src); + MessagePackObject obj = Util.unpackOne(out.toByteArray()); + Template tmpl = ByteBufferTemplate.getInstance(); + ByteBuffer dst = null; + try { + dst = (ByteBuffer) tmpl.convert(obj); + fail(); + } catch (Exception e) { + assertTrue(e instanceof MessageTypeException); + } + obj = Util.unpackOne(out.toByteArray()); + tmpl = new OptionalTemplate(ByteBufferTemplate.getInstance()); + dst = (ByteBuffer) tmpl.convert(obj); + assertEquals(src, dst); + } + @Test public void testString() throws Exception { _testString(""); diff --git a/java/src/test/java/org/msgpack/template/TestPackUnpack.java b/java/src/test/java/org/msgpack/template/TestPackUnpack.java index 29ee78da..eb171816 100644 --- a/java/src/test/java/org/msgpack/template/TestPackUnpack.java +++ b/java/src/test/java/org/msgpack/template/TestPackUnpack.java @@ -3,6 +3,7 @@ package org.msgpack.template; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.math.BigInteger; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -273,6 +274,76 @@ public class TestPackUnpack extends TestCase { assertEquals(src, dst); } + @Test + public void testByteBuffer() throws Exception { + _testByteBuffer(ByteBuffer.wrap("".getBytes())); + _testByteBuffer(ByteBuffer.wrap("a".getBytes())); + _testByteBuffer(ByteBuffer.wrap("ab".getBytes())); + _testByteBuffer(ByteBuffer.wrap("abc".getBytes())); + + // small size string + for (int i = 0; i < 100; i++) { + StringBuilder sb = new StringBuilder(); + int len = (int) Math.random() % 31 + 1; + for (int j = 0; j < len; j++) { + sb.append('a' + ((int) Math.random()) & 26); + } + _testByteBuffer(ByteBuffer.wrap(sb.toString().getBytes())); + } + + // medium size string + for (int i = 0; i < 100; i++) { + StringBuilder sb = new StringBuilder(); + int len = (int) Math.random() % 100 + (1 << 15); + for (int j = 0; j < len; j++) { + sb.append('a' + ((int) Math.random()) & 26); + } + _testByteBuffer(ByteBuffer.wrap(sb.toString().getBytes())); + } + + // large size string + for (int i = 0; i < 10; i++) { + StringBuilder sb = new StringBuilder(); + int len = (int) Math.random() % 100 + (1 << 31); + for (int j = 0; j < len; j++) { + sb.append('a' + ((int) Math.random()) & 26); + } + _testByteBuffer(ByteBuffer.wrap(sb.toString().getBytes())); + } + } + + static void _testByteBuffer(ByteBuffer src) throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + new Packer(out).pack(src); + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + Template tmpl = ByteBufferTemplate.getInstance(); + ByteBuffer dst = (ByteBuffer) tmpl.unpack(new Unpacker(in)); + assertEquals(src, dst); + } + + @Test + public void testNullByteBuffer() throws Exception { + ByteBuffer src = null; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + new Packer(out).pack(src); + byte[] bytes = out.toByteArray(); + Template tmpl = null; + Unpacker unpacker = new Unpacker(); + ByteBuffer dst = null; + try { + tmpl = ByteBufferTemplate.getInstance(); + unpacker.wrap(bytes); + dst = (ByteBuffer) tmpl.unpack(unpacker); + fail(); + } catch (Exception e) { + assertTrue(e instanceof MessageTypeException); + } + unpacker.wrap(bytes); + tmpl = new OptionalTemplate(ByteBufferTemplate.getInstance()); + dst = (ByteBuffer) tmpl.unpack(unpacker); + assertEquals(src, dst); + } + @Test public void testString() throws Exception { _testString(""); diff --git a/java/src/test/java/org/msgpack/util/codegen/TestPackConvert.java b/java/src/test/java/org/msgpack/util/codegen/TestPackConvert.java index 5ea7ce02..17347743 100644 --- a/java/src/test/java/org/msgpack/util/codegen/TestPackConvert.java +++ b/java/src/test/java/org/msgpack/util/codegen/TestPackConvert.java @@ -4,6 +4,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigInteger; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -210,6 +211,7 @@ public class TestPackConvert extends TestCase { src.f7 = new BigInteger("7"); src.f8 = "8"; src.f9 = new byte[] { 0x01, 0x02 }; + src.f10 = ByteBuffer.wrap("muga".getBytes()); ByteArrayOutputStream out = new ByteArrayOutputStream(); MessagePacker packer = DynamicPacker .create(GeneralReferenceTypeFieldsClass.class); @@ -234,6 +236,7 @@ public class TestPackConvert extends TestCase { assertEquals(src.f8, dst.f8); assertEquals(src.f9[0], dst.f9[0]); assertEquals(src.f9[1], dst.f9[1]); + assertEquals(src.f10, dst.f10); assertFalse(it.hasNext()); } @@ -268,6 +271,7 @@ public class TestPackConvert extends TestCase { public BigInteger f7; public String f8; public byte[] f9; + public ByteBuffer f10; public GeneralReferenceTypeFieldsClass() { } @@ -287,6 +291,7 @@ public class TestPackConvert extends TestCase { src.f7 = new BigInteger("7"); src.f8 = "8"; src.f9 = new byte[] { 0x01, 0x02 }; + src.f10 = ByteBuffer.wrap("muga".getBytes()); ByteArrayOutputStream out = new ByteArrayOutputStream(); MessagePacker packer = DynamicPacker .create(OptionalGeneralReferenceTypeFieldsClass.class); @@ -311,6 +316,7 @@ public class TestPackConvert extends TestCase { assertEquals(src.f8, dst.f8); assertEquals(src.f9[0], dst.f9[0]); assertEquals(src.f9[1], dst.f9[1]); + assertEquals(src.f10, dst.f10); assertFalse(it.hasNext()); } @@ -328,6 +334,7 @@ public class TestPackConvert extends TestCase { src.f7 = null; src.f8 = null; src.f9 = null; + src.f10 = null; ByteArrayOutputStream out = new ByteArrayOutputStream(); MessagePacker packer = DynamicPacker .create(OptionalGeneralReferenceTypeFieldsClass.class); @@ -351,6 +358,7 @@ public class TestPackConvert extends TestCase { assertEquals(src.f7, dst.f7); assertEquals(src.f8, dst.f8); assertEquals(src.f9, dst.f9); + assertEquals(src.f10, dst.f10); assertFalse(it.hasNext()); } @@ -396,6 +404,8 @@ public class TestPackConvert extends TestCase { public String f8; @MessagePackOptional public byte[] f9; + @MessagePackOptional + public ByteBuffer f10; public OptionalGeneralReferenceTypeFieldsClass() { } @@ -420,6 +430,10 @@ public class TestPackConvert extends TestCase { slnt.f0 = new byte[] { 0x01, 0x02 }; slnt.f1 = "muga"; src.f4.add(slnt); + src.f5 = new ArrayList(); + src.f5.add(ByteBuffer.wrap("e1".getBytes())); + src.f5.add(ByteBuffer.wrap("e2".getBytes())); + src.f5.add(ByteBuffer.wrap("e3".getBytes())); ByteArrayOutputStream out = new ByteArrayOutputStream(); MessagePacker packer = DynamicPacker.create(SampleListTypes.class); packer.pack(new Packer(out), src); @@ -456,6 +470,12 @@ public class TestPackConvert extends TestCase { assertEquals(s.f0[1], d.f0[1]); assertEquals(s.f1, d.f1); } + assertEquals(src.f5.size(), dst.f5.size()); + for (int i = 0; i < src.f4.size(); ++i) { + ByteBuffer s = src.f5.get(i); + ByteBuffer d = dst.f5.get(i); + assertEquals(s, d); + } assertFalse(it.hasNext()); } @@ -484,6 +504,7 @@ public class TestPackConvert extends TestCase { public List f2; public List> f3; public List f4; + public List f5; public SampleListTypes() { } @@ -517,6 +538,10 @@ public class TestPackConvert extends TestCase { slnt.f0 = new byte[] { 0x01, 0x02 }; slnt.f1 = "muga"; src.f4.add(slnt); + src.f5 = new ArrayList(); + src.f5.add(ByteBuffer.wrap("e1".getBytes())); + src.f5.add(ByteBuffer.wrap("e2".getBytes())); + src.f5.add(ByteBuffer.wrap("e3".getBytes())); ByteArrayOutputStream out = new ByteArrayOutputStream(); MessagePacker packer = DynamicPacker .create(SampleOptionalListTypes.class); @@ -555,6 +580,12 @@ public class TestPackConvert extends TestCase { assertEquals(s.f0[1], d.f0[1]); assertEquals(s.f1, d.f1); } + assertEquals(src.f5.size(), dst.f5.size()); + for (int i = 0; i < src.f5.size(); ++i) { + ByteBuffer s = src.f5.get(i); + ByteBuffer d = dst.f5.get(i); + assertEquals(s, d); + } assertFalse(it.hasNext()); } @@ -566,6 +597,7 @@ public class TestPackConvert extends TestCase { src.f2 = new ArrayList(); src.f3 = null; src.f4 = new ArrayList(); + src.f5 = new ArrayList(); ByteArrayOutputStream out = new ByteArrayOutputStream(); MessagePacker packer = DynamicPacker .create(SampleOptionalListTypes.class); @@ -583,6 +615,7 @@ public class TestPackConvert extends TestCase { assertEquals(src.f2.size(), dst.f2.size()); assertEquals(src.f3, dst.f3); assertEquals(src.f4.size(), dst.f4.size()); + assertEquals(src.f5.size(), dst.f5.size()); assertFalse(it.hasNext()); } @@ -617,6 +650,8 @@ public class TestPackConvert extends TestCase { public List> f3; @MessagePackOptional public List f4; + @MessagePackOptional + public List f5; public SampleOptionalListTypes() { } diff --git a/java/src/test/java/org/msgpack/util/codegen/TestPackUnpack.java b/java/src/test/java/org/msgpack/util/codegen/TestPackUnpack.java index ab276f7f..ce158e21 100644 --- a/java/src/test/java/org/msgpack/util/codegen/TestPackUnpack.java +++ b/java/src/test/java/org/msgpack/util/codegen/TestPackUnpack.java @@ -4,6 +4,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigInteger; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -201,6 +202,7 @@ public class TestPackUnpack extends TestCase { src.f7 = new BigInteger("7"); src.f8 = "8"; src.f9 = new byte[] { 0x01, 0x02 }; + src.f10 = ByteBuffer.wrap("muga".getBytes()); ByteArrayOutputStream out = new ByteArrayOutputStream(); MessagePacker packer = DynamicPacker .create(GeneralReferenceTypeFieldsClass.class); @@ -221,6 +223,7 @@ public class TestPackUnpack extends TestCase { assertEquals(src.f8, dst.f8); assertEquals(src.f9[0], dst.f9[0]); assertEquals(src.f9[1], dst.f9[1]); + assertEquals(src.f10, dst.f10); } @Test @@ -249,6 +252,7 @@ public class TestPackUnpack extends TestCase { public BigInteger f7; public String f8; public byte[] f9; + public ByteBuffer f10; public GeneralReferenceTypeFieldsClass() { } @@ -268,6 +272,7 @@ public class TestPackUnpack extends TestCase { src.f7 = new BigInteger("7"); src.f8 = "8"; src.f9 = new byte[] { 0x01, 0x02 }; + src.f10 = ByteBuffer.wrap("muga".getBytes()); ByteArrayOutputStream out = new ByteArrayOutputStream(); MessagePacker packer = DynamicPacker .create(GeneralOptionalReferenceTypeFieldsClass.class); @@ -288,6 +293,7 @@ public class TestPackUnpack extends TestCase { assertEquals(src.f8, dst.f8); assertEquals(src.f9[0], dst.f9[0]); assertEquals(src.f9[1], dst.f9[1]); + assertEquals(src.f10, dst.f10); } @Test @@ -304,6 +310,7 @@ public class TestPackUnpack extends TestCase { src.f7 = null; src.f8 = null; src.f9 = null; + src.f10 = null; ByteArrayOutputStream out = new ByteArrayOutputStream(); MessagePacker packer = DynamicPacker .create(GeneralOptionalReferenceTypeFieldsClass.class); @@ -323,6 +330,7 @@ public class TestPackUnpack extends TestCase { assertEquals(src.f7, dst.f7); assertEquals(src.f8, dst.f8); assertEquals(src.f9, dst.f9); + assertEquals(src.f10, dst.f10); } @Test @@ -362,6 +370,8 @@ public class TestPackUnpack extends TestCase { public String f8; @MessagePackOptional public byte[] f9; + @MessagePackOptional + public ByteBuffer f10; public GeneralOptionalReferenceTypeFieldsClass() { } @@ -386,6 +396,10 @@ public class TestPackUnpack extends TestCase { slnt.f0 = new byte[] { 0x01, 0x02 }; slnt.f1 = "muga"; src.f4.add(slnt); + src.f5 = new ArrayList(); + src.f5.add(ByteBuffer.wrap("e1".getBytes())); + src.f5.add(ByteBuffer.wrap("e2".getBytes())); + src.f5.add(ByteBuffer.wrap("e3".getBytes())); ByteArrayOutputStream out = new ByteArrayOutputStream(); MessagePacker packer = DynamicPacker.create(SampleListTypes.class); packer.pack(new Packer(out), src); @@ -418,6 +432,12 @@ public class TestPackUnpack extends TestCase { assertEquals(s.f0[1], d.f0[1]); assertEquals(s.f1, d.f1); } + assertEquals(src.f5.size(), dst.f5.size()); + for (int i = 0; i < src.f5.size(); ++i) { + ByteBuffer s = src.f5.get(i); + ByteBuffer d = dst.f5.get(i); + assertEquals(s, d); + } } @Test @@ -440,6 +460,7 @@ public class TestPackUnpack extends TestCase { public List f2; public List> f3; public List f4; + public List f5; public SampleListTypes() { } @@ -473,6 +494,10 @@ public class TestPackUnpack extends TestCase { slnt.f0 = new byte[] { 0x01, 0x02 }; slnt.f1 = "muga"; src.f4.add(slnt); + src.f5 = new ArrayList(); + src.f5.add(ByteBuffer.wrap("e1".getBytes())); + src.f5.add(ByteBuffer.wrap("e2".getBytes())); + src.f5.add(ByteBuffer.wrap("e3".getBytes())); ByteArrayOutputStream out = new ByteArrayOutputStream(); MessagePacker packer = DynamicPacker .create(SampleOptionalListTypes.class); @@ -507,6 +532,12 @@ public class TestPackUnpack extends TestCase { assertEquals(s.f0[1], d.f0[1]); assertEquals(s.f1, d.f1); } + assertEquals(src.f5.size(), dst.f5.size()); + for (int i = 0; i < src.f5.size(); ++i) { + ByteBuffer s = src.f5.get(i); + ByteBuffer d = dst.f5.get(i); + assertEquals(s, d); + } } @Test @@ -517,6 +548,7 @@ public class TestPackUnpack extends TestCase { src.f2 = new ArrayList(); src.f3 = new ArrayList>(); src.f4 = null; + src.f5 = new ArrayList(); ByteArrayOutputStream out = new ByteArrayOutputStream(); MessagePacker packer = DynamicPacker .create(SampleOptionalListTypes.class); @@ -530,6 +562,7 @@ public class TestPackUnpack extends TestCase { assertEquals(src.f2.size(), dst.f2.size()); assertEquals(src.f3.size(), dst.f3.size()); assertEquals(src.f4, dst.f4); + assertEquals(src.f5.size(), dst.f5.size()); } @Test @@ -557,6 +590,8 @@ public class TestPackUnpack extends TestCase { public List> f3; @MessagePackOptional public List f4; + @MessagePackOptional + public List f5; public SampleOptionalListTypes() { }