diff --git a/.gitignore b/.gitignore index b39017b2..305f896a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,10 @@ ruby/Makefile *.6 _obj _test +/csharp/MsgPack.suo +/csharp/MsgPack/bin +/csharp/MsgPack/obj +/csharp/MsgPack/MsgPack.csproj.user +/csharp/MsgPack.Test/obj +/csharp/MsgPack.Test/bin +/csharp/MsgPack.Test/MsgPack.Test.csproj.user diff --git a/cpp/ChangeLog b/cpp/ChangeLog index 6d7f486d..a14807c8 100644 --- a/cpp/ChangeLog +++ b/cpp/ChangeLog @@ -1,4 +1,8 @@ +2011-04-24 version 0.5.6: + + * #42 fixes double-free problem on msgpack_unpacker_release_zone + 2011-02-24 version 0.5.5: * eliminates dependency of winsock2.h header diff --git a/cpp/configure.in b/cpp/configure.in index f017b7cf..95635c3c 100644 --- a/cpp/configure.in +++ b/cpp/configure.in @@ -1,6 +1,6 @@ AC_INIT(src/object.cpp) AC_CONFIG_AUX_DIR(ac) -AM_INIT_AUTOMAKE(msgpack, 0.5.5) +AM_INIT_AUTOMAKE(msgpack, 0.5.6) AC_CONFIG_HEADER(config.h) AC_SUBST(CFLAGS) diff --git a/cpp/src/msgpack/unpack.hpp b/cpp/src/msgpack/unpack.hpp index 51580b6e..baca1176 100644 --- a/cpp/src/msgpack/unpack.hpp +++ b/cpp/src/msgpack/unpack.hpp @@ -258,17 +258,7 @@ inline object unpacker::data() inline zone* unpacker::release_zone() { - if(!msgpack_unpacker_flush_zone(this)) { - throw std::bad_alloc(); - } - - zone* r = new zone(); - - msgpack_zone old = *base::z; - *base::z = *r; - *static_cast(r) = old; - - return r; + return static_cast(msgpack_unpacker_release_zone(static_cast(this))); } inline void unpacker::reset_zone() diff --git a/cpp/src/unpack.c b/cpp/src/unpack.c index 52b834c9..d66dc56b 100644 --- a/cpp/src/unpack.c +++ b/cpp/src/unpack.c @@ -337,6 +337,7 @@ msgpack_zone* msgpack_unpacker_release_zone(msgpack_unpacker* mpac) msgpack_zone* old = mpac->z; mpac->z = r; + CTX_CAST(mpac->ctx)->user.z = mpac->z; return old; } diff --git a/cpp/test/streaming_c.cc b/cpp/test/streaming_c.cc index 6c87ac6d..1b7ad8b6 100644 --- a/cpp/test/streaming_c.cc +++ b/cpp/test/streaming_c.cc @@ -7,9 +7,21 @@ TEST(streaming, basic) msgpack_sbuffer* buffer = msgpack_sbuffer_new(); msgpack_packer* pk = msgpack_packer_new(buffer, msgpack_sbuffer_write); + + // 1, 2, 3, "raw", ["data"], {0.3: 0.4} EXPECT_EQ(0, msgpack_pack_int(pk, 1)); EXPECT_EQ(0, msgpack_pack_int(pk, 2)); EXPECT_EQ(0, msgpack_pack_int(pk, 3)); + EXPECT_EQ(0, msgpack_pack_raw(pk, 3)); + EXPECT_EQ(0, msgpack_pack_raw_body(pk, "raw", 3)); + EXPECT_EQ(0, msgpack_pack_array(pk, 1)); + EXPECT_EQ(0, msgpack_pack_raw(pk, 4)); + EXPECT_EQ(0, msgpack_pack_raw_body(pk, "data", 4)); + EXPECT_EQ(0, msgpack_pack_map(pk, 1)); + EXPECT_EQ(0, msgpack_pack_float(pk, 0.4)); + EXPECT_EQ(0, msgpack_pack_double(pk, 0.8)); + int max_count = 6; + msgpack_packer_free(pk); const char* input = buffer->data; @@ -22,36 +34,65 @@ TEST(streaming, basic) msgpack_unpacked_init(&result); int count = 0; - while(count < 3) { + while(count < max_count) { + bool unpacked = false; + msgpack_unpacker_reserve_buffer(&pac, 32*1024); - /* read buffer into msgpack_unapcker_buffer(&pac) upto - * msgpack_unpacker_buffer_capacity(&pac) bytes. */ - size_t len = 1; - memcpy(msgpack_unpacker_buffer(&pac), input, len); - input += len; + while(!unpacked) { + /* read buffer into msgpack_unapcker_buffer(&pac) upto + * msgpack_unpacker_buffer_capacity(&pac) bytes. */ + memcpy(msgpack_unpacker_buffer(&pac), input, 1); + input += 1; - msgpack_unpacker_buffer_consumed(&pac, len); + EXPECT_TRUE(input <= eof); - while(msgpack_unpacker_next(&pac, &result)) { - msgpack_object obj = result.data; - switch(count++) { - case 0: - EXPECT_EQ(MSGPACK_OBJECT_POSITIVE_INTEGER, result.data.type); - EXPECT_EQ(1, result.data.via.u64); - break; - case 1: - EXPECT_EQ(MSGPACK_OBJECT_POSITIVE_INTEGER, result.data.type); - EXPECT_EQ(2, result.data.via.u64); - break; - case 2: - EXPECT_EQ(MSGPACK_OBJECT_POSITIVE_INTEGER, result.data.type); - EXPECT_EQ(3, result.data.via.u64); - return; + msgpack_unpacker_buffer_consumed(&pac, 1); + + while(msgpack_unpacker_next(&pac, &result)) { + unpacked = 1; + msgpack_object obj = result.data; + msgpack_object e; + switch(count++) { + case 0: + EXPECT_EQ(MSGPACK_OBJECT_POSITIVE_INTEGER, obj.type); + EXPECT_EQ(1, obj.via.u64); + break; + case 1: + EXPECT_EQ(MSGPACK_OBJECT_POSITIVE_INTEGER, obj.type); + EXPECT_EQ(2, obj.via.u64); + break; + case 2: + EXPECT_EQ(MSGPACK_OBJECT_POSITIVE_INTEGER, obj.type); + EXPECT_EQ(3, obj.via.u64); + break; + case 3: + EXPECT_EQ(MSGPACK_OBJECT_RAW, obj.type); + EXPECT_EQ(std::string("raw",3), std::string(obj.via.raw.ptr, obj.via.raw.size)); + break; + case 4: + EXPECT_EQ(MSGPACK_OBJECT_ARRAY, obj.type); + EXPECT_EQ(1, obj.via.array.size); + e = obj.via.array.ptr[0]; + EXPECT_EQ(MSGPACK_OBJECT_RAW, e.type); + EXPECT_EQ(std::string("data",4), std::string(e.via.raw.ptr, e.via.raw.size)); + break; + case 5: + EXPECT_EQ(MSGPACK_OBJECT_MAP, obj.type); + EXPECT_EQ(1, obj.via.map.size); + e = obj.via.map.ptr[0].key; + EXPECT_EQ(MSGPACK_OBJECT_DOUBLE, e.type); + ASSERT_FLOAT_EQ(0.4, (float)e.via.dec); + e = obj.via.map.ptr[0].val; + EXPECT_EQ(MSGPACK_OBJECT_DOUBLE, e.type); + ASSERT_DOUBLE_EQ(0.8, e.via.dec); + break; + } } } - - EXPECT_TRUE(input < eof); } + + msgpack_unpacker_destroy(&pac); + msgpack_unpacked_destroy(&result); } diff --git a/csharp/Makefile b/csharp/Makefile new file mode 100644 index 00000000..9cf6a243 --- /dev/null +++ b/csharp/Makefile @@ -0,0 +1,21 @@ +TARGET=MsgPack.dll +TEST_TARGET=MsgPack.Test.dll + +SRC=$(shell find MsgPack -name "*.cs") +TEST_SRC=$(shell find MsgPack.Test -name "*.cs") + +MONO_CC=mcs +NUNIT_CONSOLE=nunit-console + +all: $(TARGET) +test: $(TEST_TARGET) $(TARGET) +clean: + rm -f $(TARGET) $(TEST_TARGET) +run-test: + $(NUNIT_CONSOLE) $(TEST_TARGET) + +$(TARGET): $(SRC) + $(MONO_CC) -out:$@ -t:library -unsafe+ $(SRC) + +$(TEST_TARGET): $(TEST_SRC) $(TARGET) + $(MONO_CC) -out:$@ -t:library -r:$(TARGET) -r:nunit.framework.dll $(TEST_SRC) diff --git a/csharp/MsgPack.Test/AssemblyInfo.cs b/csharp/MsgPack.Test/AssemblyInfo.cs new file mode 100644 index 00000000..307c6a90 --- /dev/null +++ b/csharp/MsgPack.Test/AssemblyInfo.cs @@ -0,0 +1,26 @@ +// +// Copyright 2011 Kazuki Oikawa +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle ("MsgPack UnitTest")] +[assembly: AssemblyProduct ("MsgPack UnitTest")] +[assembly: AssemblyDescription ("MessagePack Serializer for .NET UnitTests")] +[assembly: AssemblyCopyright ("Copyright © 2011 Kazuki Oikawa")] + +[assembly: ComVisible (false)] +[assembly: AssemblyVersion ("0.1.*")] diff --git a/csharp/MsgPack.Test/BoxingPackerTests.cs b/csharp/MsgPack.Test/BoxingPackerTests.cs new file mode 100644 index 00000000..a39a3c89 --- /dev/null +++ b/csharp/MsgPack.Test/BoxingPackerTests.cs @@ -0,0 +1,89 @@ +// +// Copyright 2011 Kazuki Oikawa +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; + +namespace MsgPack.Test +{ + [TestFixture] + public class BoxingPackerTests + { + [Test] + public void NullTest () + { + BoxingPacker packer = new BoxingPacker (); + Assert.IsNull (packer.Unpack (packer.Pack (null))); + } + + [Test] + public void PrimitiveTypeTest () + { + BoxingPacker packer = new BoxingPacker (); + RoundtripTest (packer, 12345); + RoundtripTest (packer, 1234567890123456789UL); + RoundtripTest (packer, Math.PI); + RoundtripTest (packer, true); + RoundtripTest (packer, false); + } + + [Test] + public void ArrayTest () + { + BoxingPacker packer = new BoxingPacker (); + RoundtripTest (packer, new object[0]); + RoundtripTest (packer, new object[]{ + int.MinValue, int.MaxValue, 1234567890123456789UL, ulong.MaxValue, + float.MinValue, float.MaxValue, float.Epsilon, float.NaN, float.PositiveInfinity, float.NegativeInfinity, + double.MinValue, double.MaxValue, double.Epsilon, double.NaN, double.PositiveInfinity, double.NegativeInfinity, + null, true, false, new object[] { + new object[] {1, 2, 3}, + new object[] {Math.PI, true} + } + }); + } + + [Test] + public void MapTest () + { + BoxingPacker packer = new BoxingPacker (); + Dictionary dic = new Dictionary (); + Dictionary dic2 = new Dictionary (); + RoundtripTest> (packer, dic); + + dic2.Add (123, 456); + dic2.Add (234, 567); + dic2.Add (345, 678); + + dic.Add (0, 0.123); + dic.Add (Math.PI, true); + dic.Add (false, new object[] {1, 2, 3}); + dic.Add (1, new Dictionary (dic2)); + RoundtripTest> (packer, dic); + + dic[1] = ((Dictionary)dic[1]).ToArray (); + Assert.AreEqual (dic, packer.Unpack (packer.Pack (dic.ToArray ()))); + } + + void RoundtripTest (BoxingPacker packer, T obj) + { + T obj2 = (T)packer.Unpack (packer.Pack (obj)); + Assert.AreEqual (obj, obj2); + } + } +} diff --git a/csharp/MsgPack.Test/CompiledPackerTests.cs b/csharp/MsgPack.Test/CompiledPackerTests.cs new file mode 100644 index 00000000..16daef9b --- /dev/null +++ b/csharp/MsgPack.Test/CompiledPackerTests.cs @@ -0,0 +1,67 @@ +// +// Copyright 2011 Kazuki Oikawa +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using NUnit.Framework; +using TestA_Class = MsgPack.Test.ObjectPackerTests.TestA_Class; +using TestB_Class = MsgPack.Test.ObjectPackerTests.TestB_Class; + +namespace MsgPack.Test +{ + [TestFixture] + public class CompiledPackerTests + { + CompiledPacker _mbImpl = new CompiledPacker (false); + CompiledPacker _dynImpl = new CompiledPacker (true); + + [Test] + public void TestA_MethodBuilder () + { + TestA (_mbImpl); + } + + [Test] + public void TestA_DynamicMethod () + { + TestA (_dynImpl); + } + + [Test] + public void TestB_MethodBuilder () + { + TestB (_mbImpl); + } + + [Test] + public void TestB_DynamicMethod () + { + TestB (_dynImpl); + } + + void TestA (CompiledPacker packer) + { + TestA_Class obj0 = new TestA_Class (); + TestA_Class obj1 = packer.Unpack (packer.Pack (obj0)); + obj0.Check (obj1); + } + + void TestB (CompiledPacker packer) + { + TestB_Class obj0 = TestB_Class.Create (); + TestB_Class obj1 = packer.Unpack (packer.Pack (obj0)); + obj0.Check (obj1); + } + } +} diff --git a/csharp/MsgPack.Test/MsgPack.Test.csproj b/csharp/MsgPack.Test/MsgPack.Test.csproj new file mode 100644 index 00000000..e00c3cca --- /dev/null +++ b/csharp/MsgPack.Test/MsgPack.Test.csproj @@ -0,0 +1,65 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {CE24167B-8F0A-4670-BD1E-3C283311E86B} + Library + Properties + MsgPack.Test + MsgPack.Test + v4.0 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + true + full + false + bin\Debug\ + TRACE;DEBUG + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + False + + + + + + + + + + + + + + {E1809531-EC2A-4EA6-B0E8-CC815EDFAA2F} + MsgPack + + + + + \ No newline at end of file diff --git a/csharp/MsgPack.Test/ObjectPackerTests.cs b/csharp/MsgPack.Test/ObjectPackerTests.cs new file mode 100644 index 00000000..26f3d3bc --- /dev/null +++ b/csharp/MsgPack.Test/ObjectPackerTests.cs @@ -0,0 +1,131 @@ +// +// Copyright 2011 Kazuki Oikawa +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using NUnit.Framework; + +namespace MsgPack.Test +{ + [TestFixture] + public class ObjectPackerTests + { + [Test] + public void TestA () + { + ObjectPacker packer = new ObjectPacker (); + TestA_Class obj0 = new TestA_Class (); + TestA_Class obj1 = packer.Unpack (packer.Pack (obj0)); + obj0.Check (obj1); + } + + [Test] + public void TestB () + { + ObjectPacker packer = new ObjectPacker (); + TestB_Class obj0 = TestB_Class.Create (); + TestB_Class obj1 = packer.Unpack (packer.Pack (obj0)); + obj0.Check (obj1); + } + + public class TestA_Class + { + public bool a; + public byte b; + public sbyte c; + public short d; + public ushort e; + public int f; + public uint g; + public long h; + public ulong i; + public float j; + public double k; + public int[] l; + public string m; + + public TestA_Class () + { + Random rnd = new Random (); + a = rnd.NextDouble () < 0.5; + b = (byte)rnd.Next (); + c = (sbyte)rnd.Next (); + d = (short)rnd.Next (); + e = (ushort)rnd.Next (); + f = (int)rnd.Next (); + g = (uint)rnd.Next (); + h = (long)rnd.Next (); + i = (ulong)rnd.Next (); + j = (float)rnd.NextDouble (); + k = (double)rnd.NextDouble (); + l = new int[rnd.Next () & 0xff]; + for (int z = 0; z < l.Length; z ++) + l[z] = rnd.Next (); + + byte[] buf = new byte[rnd.Next() & 0xff]; + rnd.NextBytes (buf); + m = Convert.ToBase64String (buf); + } + + public void Check (TestA_Class other) + { + Assert.AreEqual (this.a, other.a); + Assert.AreEqual (this.b, other.b); + Assert.AreEqual (this.c, other.c); + Assert.AreEqual (this.d, other.d); + Assert.AreEqual (this.e, other.e); + Assert.AreEqual (this.f, other.f); + Assert.AreEqual (this.g, other.g); + Assert.AreEqual (this.h, other.h); + Assert.AreEqual (this.i, other.i); + Assert.AreEqual (this.j, other.j); + Assert.AreEqual (this.k, other.k); + Assert.AreEqual (this.l, other.l); + Assert.AreEqual (this.m, other.m); + } + } + + public class TestB_Class + { + public TestA_Class x; + public TestB_Class nested; + public int[] list; + + public static TestB_Class Create () + { + return Create (0); + } + + static TestB_Class Create (int level) + { + TestB_Class obj = new TestB_Class (); + obj.x = new TestA_Class (); + if (level < 10) + obj.nested = Create (level + 1); + if ((level % 2) == 0) + obj.list = new int[] {level, 0, level, int.MaxValue, level}; + return obj; + } + + public void Check (TestB_Class other) + { + x.Check (other.x); + if (nested != null) + nested.Check (other.nested); + Assert.AreEqual (list, other.list); + } + } + } +} diff --git a/csharp/MsgPack.Test/ReaderWriterTests.cs b/csharp/MsgPack.Test/ReaderWriterTests.cs new file mode 100644 index 00000000..5971285b --- /dev/null +++ b/csharp/MsgPack.Test/ReaderWriterTests.cs @@ -0,0 +1,331 @@ +// +// Copyright 2011 Kazuki Oikawa +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.IO; +using NUnit.Framework; + +namespace MsgPack.Test +{ + [TestFixture] + public class ReaderWriterTests + { + [Test] + public void SignedNumberTest () + { + long[] nums = new long[]{ + /* positive fixnum */ + 0, 1, 126, 127, + + /* negative fixnum */ + -1, -2, -31, -32, + + /* int8 */ + -128, -33, + + /* int16 */ + -32768, -129, 128, 32767, + + /* int32 */ + -2147483648, -32769, 32768, 2147483647, + + /* int64 */ + -9223372036854775808, -2147483649, 2147483648, 9223372036854775807 + }; + byte[] expectedBytes = new byte[] { + /* positive fixnum */ + 0, 1, 126, 127, + + /* negative fixnum */ + 0xff, 0xfe, 0xe1, 0xe0, + + /* int8 */ + 0xd0, 0x80, + 0xd0, 0xdf, + + /* int16 */ + 0xd1, 0x80, 0x00, + 0xd1, 0xff, 0x7f, + 0xd1, 0x00, 0x80, + 0xd1, 0x7f, 0xff, + + /* int32 */ + 0xd2, 0x80, 0x00, 0x00, 0x00, + 0xd2, 0xff, 0xff, 0x7f, 0xff, + 0xd2, 0x00, 0x00, 0x80, 0x00, + 0xd2, 0x7f, 0xff, 0xff, 0xff, + + /* int64 */ + 0xd3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd3, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, + 0xd3, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0xd3, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + Test (delegate (MsgPackWriter writer) { + for (int i = 0; i < nums.Length; i ++) { + writer.Write (nums[i]); + } + }, delegate (MsgPackReader reader) { + for (int i = 0; i < nums.Length; i ++) { + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.IsSigned () || reader.IsSigned64 ()); + if (reader.IsSigned64 ()) { + Assert.AreEqual (nums[i], reader.ValueSigned64); + } else { + Assert.AreEqual (nums[i], reader.ValueSigned); + } + } + }, expectedBytes); + } + + [Test] + public void UnsignedNumberTest () + { + ulong[] nums = new ulong[]{ + /* uint8 */ + 128, byte.MaxValue, + + /* uint16 */ + byte.MaxValue + 1, ushort.MaxValue, + + /* uint32 */ + ushort.MaxValue + 1U, uint.MaxValue, + + /* uint64 */ + uint.MaxValue + 1UL, ulong.MaxValue + }; + byte[] expectedBytes = new byte[] { + /* int8 */ + 0xcc, 0x80, + 0xcc, 0xff, + + /* int16 */ + 0xcd, 0x01, 0x00, + 0xcd, 0xff, 0xff, + + /* int32 */ + 0xce, 0x00, 0x01, 0x00, 0x00, + 0xce, 0xff, 0xff, 0xff, 0xff, + + /* int64 */ + 0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + Test (delegate (MsgPackWriter writer) { + for (int i = 0; i < nums.Length; i ++) { + writer.Write (nums[i]); + } + }, delegate (MsgPackReader reader) { + for (int i = 0; i < nums.Length; i ++) { + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.IsUnsigned () || reader.IsUnsigned64 ()); + if (reader.IsUnsigned64 ()) { + Assert.AreEqual (nums[i], reader.ValueUnsigned64); + } else { + Assert.AreEqual (nums[i], reader.ValueUnsigned); + } + } + }, expectedBytes); + } + + [Test] + public void NilTest () + { + byte[] expectedBytes = new byte[] { + 0xc0 + }; + + Test (delegate (MsgPackWriter writer) { + writer.WriteNil (); + }, delegate (MsgPackReader reader) { + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.Type == TypePrefixes.Nil); + }, expectedBytes); + } + + [Test] + public void BooleanTest () + { + byte[] expectedBytes = new byte[] { + 0xc3, 0xc2 + }; + + Test (delegate (MsgPackWriter writer) { + writer.Write (true); + writer.Write (false); + }, delegate (MsgPackReader reader) { + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.Type == TypePrefixes.True); + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.Type == TypePrefixes.False); + }, expectedBytes); + } + + [Test] + public void FloatingPointTest () + { + byte[] expectedBytes = new byte[] { + 0xca, 0x40, 0x49, 0x0f, 0xdb, + 0xcb, 0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18, + }; + + Test (delegate (MsgPackWriter writer) { + writer.Write ((float)Math.PI); + writer.Write (Math.PI); + }, delegate (MsgPackReader reader) { + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.Type == TypePrefixes.Float); + Assert.AreEqual ((float)Math.PI, reader.ValueFloat); + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.Type == TypePrefixes.Double); + Assert.AreEqual (Math.PI, reader.ValueDouble); + }, expectedBytes); + } + + [Test] + public void RawTest () + { + Random rnd = new Random (); + + byte[][] rawList = new byte[][] { + new byte[0], + new byte[1], + new byte[31], + new byte[32], + new byte[65535], + new byte[65536] + }; + byte[][] headerSizeList = new byte[][] { + new byte[] {0xa0}, + new byte[] {0xa1}, + new byte[] {0xbf}, + new byte[] {0xda, 0x00, 0x20}, + new byte[] {0xda, 0xff, 0xff}, + new byte[] {0xdb, 0x00, 0x01, 0x00, 0x00}, + }; + byte[] expectedBytes = new byte[131135 + 1 * 3 + 3 * 2 + 5]; + for (int i = 0, offset = 0; i < rawList.Length; i ++) { + rnd.NextBytes (rawList[i]); + + Buffer.BlockCopy (headerSizeList[i], 0, expectedBytes, offset, headerSizeList[i].Length); + offset += headerSizeList[i].Length; + Buffer.BlockCopy (rawList[i], 0, expectedBytes, offset, rawList[i].Length); + offset += rawList[i].Length; + } + + Test (delegate (MsgPackWriter writer) { + for (int i = 0; i < rawList.Length; i ++) + writer.Write (rawList[i]); + }, delegate (MsgPackReader reader) { + for (int i = 0; i < rawList.Length; i ++) { + Assert.IsTrue (reader.Read ()); + Assert.AreEqual (rawList[i].Length, (int)reader.Length); + byte[] tmp = new byte[(int)reader.Length]; + reader.ReadValueRaw (tmp, 0, tmp.Length); + Assert.AreEqual (rawList[i], tmp); + } + }, expectedBytes); + } + + [Test] + public void ArrayMapRawHeaderTest () + { + int[] list = new int[] { + 0, 1, 15, 16, 31, 32, 65535, 65536 + }; + byte[] expectedBytes = new byte[] { + /* size=0 */ + 0x90, /* array */ + 0x80, /* map */ + 0xa0, /* raw */ + + /* size=1 */ + 0x91, + 0x81, + 0xa1, + + /* size=15 */ + 0x9f, + 0x8f, + 0xaf, + + /* size=16 */ + 0xdc, 0x00, 0x10, /* array16 */ + 0xde, 0x00, 0x10, /* map16 */ + 0xb0, /* fix raw */ + + /* size=31 */ + 0xdc, 0x00, 0x1f, /* array16 */ + 0xde, 0x00, 0x1f, /* map16 */ + 0xbf, /* fix raw */ + + /* size=32 */ + 0xdc, 0x00, 0x20, /* array16 */ + 0xde, 0x00, 0x20, /* map16 */ + 0xda, 0x00, 0x20, /* raw16 */ + + /* size=65535 */ + 0xdc, 0xff, 0xff, /* array16 */ + 0xde, 0xff, 0xff, /* map16 */ + 0xda, 0xff, 0xff, /* raw16 */ + + /* size=65536 */ + 0xdd, 0x00, 0x01, 0x00, 0x00, /* array32 */ + 0xdf, 0x00, 0x01, 0x00, 0x00, /* map32 */ + 0xdb, 0x00, 0x01, 0x00, 0x00, /* raw32 */ + }; + + Test (delegate (MsgPackWriter writer) { + for (int i = 0; i < list.Length; i ++) { + writer.WriteArrayHeader (list[i]); + writer.WriteMapHeader (list[i]); + writer.WriteRawHeader (list[i]); + } + }, delegate (MsgPackReader reader) { + for (int i = 0; i < list.Length; i ++) { + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.IsArray ()); + Assert.AreEqual (list[i], (int)reader.Length); + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.IsMap ()); + Assert.AreEqual (list[i], (int)reader.Length); + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.IsRaw ()); + Assert.AreEqual (list[i], (int)reader.Length); + } + }, expectedBytes); + } + + delegate void WriteDelegate (MsgPackWriter writer); + delegate void ReadDelegate (MsgPackReader reader); + void Test (WriteDelegate writeProc, ReadDelegate readProc, byte[] expectedBytes) + { + byte[] raw; + using (MemoryStream ms = new MemoryStream ()) { + MsgPackWriter writer = new MsgPackWriter (ms); + writeProc (writer); + raw = ms.ToArray (); + } + Assert.AreEqual (expectedBytes, raw, "pack failed"); + using (MemoryStream ms = new MemoryStream (raw)) { + MsgPackReader reader = new MsgPackReader (ms); + readProc (reader); + } + } + } +} diff --git a/csharp/MsgPack.sln b/csharp/MsgPack.sln new file mode 100644 index 00000000..3cdebef0 --- /dev/null +++ b/csharp/MsgPack.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MsgPack", "MsgPack\MsgPack.csproj", "{E1809531-EC2A-4EA6-B0E8-CC815EDFAA2F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MsgPack.Test", "MsgPack.Test/MsgPack.Test.csproj", "{CE24167B-8F0A-4670-BD1E-3C283311E86B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E1809531-EC2A-4EA6-B0E8-CC815EDFAA2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E1809531-EC2A-4EA6-B0E8-CC815EDFAA2F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E1809531-EC2A-4EA6-B0E8-CC815EDFAA2F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E1809531-EC2A-4EA6-B0E8-CC815EDFAA2F}.Release|Any CPU.Build.0 = Release|Any CPU + {CE24167B-8F0A-4670-BD1E-3C283311E86B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE24167B-8F0A-4670-BD1E-3C283311E86B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE24167B-8F0A-4670-BD1E-3C283311E86B}.Release|Any CPU.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/csharp/MsgPack/AssemblyInfo.cs b/csharp/MsgPack/AssemblyInfo.cs new file mode 100644 index 00000000..27f88372 --- /dev/null +++ b/csharp/MsgPack/AssemblyInfo.cs @@ -0,0 +1,28 @@ +// +// Copyright 2011 Kazuki Oikawa +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle ("MsgPack")] +[assembly: AssemblyProduct ("MsgPack")] +[assembly: AssemblyDescription ("MessagePack Serializer for .NET")] +[assembly: AssemblyCopyright ("Copyright © 2011 Kazuki Oikawa")] + +[assembly: ComVisible (false)] +[assembly: AssemblyVersion ("0.1.*")] +[assembly: InternalsVisibleTo (MsgPack.CompiledPacker.MethodBuilderPacker.AssemblyName)] diff --git a/csharp/MsgPack/BoxingPacker.cs b/csharp/MsgPack/BoxingPacker.cs new file mode 100644 index 00000000..05466835 --- /dev/null +++ b/csharp/MsgPack/BoxingPacker.cs @@ -0,0 +1,184 @@ +// +// Copyright 2011 Kazuki Oikawa +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Reflection; + +namespace MsgPack +{ + public class BoxingPacker + { + static Type KeyValuePairDefinitionType; + + static BoxingPacker () + { + KeyValuePairDefinitionType = typeof (KeyValuePair).GetGenericTypeDefinition (); + } + + public void Pack (Stream strm, object o) + { + MsgPackWriter writer = new MsgPackWriter (strm); + Pack (writer, o); + } + + public byte[] Pack (object o) + { + using (MemoryStream ms = new MemoryStream ()) { + Pack (ms, o); + return ms.ToArray (); + } + } + + void Pack (MsgPackWriter writer, object o) + { + if (o == null) { + writer.WriteNil (); + return; + } + + Type t = o.GetType (); + if (t.IsPrimitive) { + if (t.Equals (typeof (int))) writer.Write ((int)o); + else if (t.Equals (typeof (uint))) writer.Write ((uint)o); + else if (t.Equals (typeof (float))) writer.Write ((float)o); + else if (t.Equals (typeof (double))) writer.Write ((double)o); + else if (t.Equals (typeof (long))) writer.Write ((long)o); + else if (t.Equals (typeof (ulong))) writer.Write ((ulong)o); + else if (t.Equals (typeof (bool))) writer.Write ((bool)o); + else if (t.Equals (typeof (byte))) writer.Write ((byte)o); + else if (t.Equals (typeof (sbyte))) writer.Write ((sbyte)o); + else if (t.Equals (typeof (short))) writer.Write ((short)o); + else if (t.Equals (typeof (ushort))) writer.Write ((ushort)o); + else throw new NotSupportedException (); // char? + return; + } + + IDictionary dic = o as IDictionary; + if (dic != null) { + writer.WriteMapHeader (dic.Count); + foreach (System.Collections.DictionaryEntry e in dic) { + Pack (writer, e.Key); + Pack (writer, e.Value); + } + return; + } + + if (t.IsArray) { + Array ary = (Array)o; + Type et = t.GetElementType (); + + // KeyValuePair[] (Map Type) + if (et.IsGenericType && et.GetGenericTypeDefinition ().Equals (KeyValuePairDefinitionType)) { + PropertyInfo propKey = et.GetProperty ("Key"); + PropertyInfo propValue = et.GetProperty ("Value"); + writer.WriteMapHeader (ary.Length); + for (int i = 0; i < ary.Length; i ++) { + object e = ary.GetValue (i); + Pack (writer, propKey.GetValue (e, null)); + Pack (writer, propValue.GetValue (e, null)); + } + return; + } + + // Array + writer.WriteArrayHeader (ary.Length); + for (int i = 0; i < ary.Length; i ++) + Pack (writer, ary.GetValue (i)); + return; + } + } + + public object Unpack (Stream strm) + { + MsgPackReader reader = new MsgPackReader (strm); + return Unpack (reader); + } + + public object Unpack (byte[] buf, int offset, int size) + { + using (MemoryStream ms = new MemoryStream (buf, offset, size)) { + return Unpack (ms); + } + } + + public object Unpack (byte[] buf) + { + return Unpack (buf, 0, buf.Length); + } + + object Unpack (MsgPackReader reader) + { + if (!reader.Read ()) + throw new FormatException (); + + switch (reader.Type) { + case TypePrefixes.PositiveFixNum: + case TypePrefixes.NegativeFixNum: + case TypePrefixes.Int8: + case TypePrefixes.Int16: + case TypePrefixes.Int32: + return reader.ValueSigned; + case TypePrefixes.Int64: + return reader.ValueSigned64; + case TypePrefixes.UInt8: + case TypePrefixes.UInt16: + case TypePrefixes.UInt32: + return reader.ValueUnsigned; + case TypePrefixes.UInt64: + return reader.ValueUnsigned64; + case TypePrefixes.True: + return true; + case TypePrefixes.False: + return false; + case TypePrefixes.Float: + return reader.ValueFloat; + case TypePrefixes.Double: + return reader.ValueDouble; + case TypePrefixes.Nil: + return null; + case TypePrefixes.FixRaw: + case TypePrefixes.Raw16: + case TypePrefixes.Raw32: + byte[] raw = new byte[reader.Length]; + reader.ReadValueRaw (raw, 0, raw.Length); + return raw; + case TypePrefixes.FixArray: + case TypePrefixes.Array16: + case TypePrefixes.Array32: + object[] ary = new object[reader.Length]; + for (int i = 0; i < ary.Length; i ++) + ary[i] = Unpack (reader); + return ary; + case TypePrefixes.FixMap: + case TypePrefixes.Map16: + case TypePrefixes.Map32: + IDictionary dic = new Dictionary ((int)reader.Length); + int count = (int)reader.Length; + for (int i = 0; i < count; i ++) { + object k = Unpack (reader); + object v = Unpack (reader); + dic.Add (k, v); + } + return dic; + default: + throw new FormatException (); + } + } + } +} diff --git a/csharp/MsgPack/CompiledPacker.cs b/csharp/MsgPack/CompiledPacker.cs new file mode 100644 index 00000000..1d4b7477 --- /dev/null +++ b/csharp/MsgPack/CompiledPacker.cs @@ -0,0 +1,549 @@ +// +// Copyright 2011 Kazuki Oikawa +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Reflection.Emit; +using System.Threading; +using MsgPack.Compiler; + +namespace MsgPack +{ + public class CompiledPacker + { + static PackerBase _publicFieldPacker, _allFieldPacker; + PackerBase _packer; + + static CompiledPacker () + { + _publicFieldPacker = new MethodBuilderPacker (); + _allFieldPacker = new DynamicMethodPacker (); + } + + public CompiledPacker () : this (false) {} + public CompiledPacker (bool packPrivateField) + { + _packer = (packPrivateField ? _allFieldPacker : _publicFieldPacker); + } + + public void Prepare () + { + _packer.CreatePacker (); + _packer.CreateUnpacker (); + } + + #region Generics Pack/Unpack Methods + public byte[] Pack (T o) + { + using (MemoryStream ms = new MemoryStream ()) { + Pack (ms, o); + return ms.ToArray (); + } + } + + public void Pack (Stream strm, T o) + { + _packer.CreatePacker () (new MsgPackWriter (strm), o); + } + + public T Unpack (byte[] buf) + { + return Unpack (buf, 0, buf.Length); + } + + public T Unpack (byte[] buf, int offset, int size) + { + using (MemoryStream ms = new MemoryStream (buf, offset, size)) { + return Unpack (ms); + } + } + + public T Unpack (Stream strm) + { + return _packer.CreateUnpacker () (new MsgPackReader (strm)); + } + #endregion + + #region Non-generics Pack/Unpack Methods + public byte[] Pack (object o) + { + using (MemoryStream ms = new MemoryStream ()) { + Pack (ms, o); + return ms.ToArray (); + } + } + + public void Pack (Stream strm, object o) + { + throw new NotImplementedException (); + } + + public object Unpack (Type t, byte[] buf) + { + return Unpack (t, buf, 0, buf.Length); + } + + public object Unpack (Type t, byte[] buf, int offset, int size) + { + using (MemoryStream ms = new MemoryStream (buf, offset, size)) { + return Unpack (t, ms); + } + } + + public object Unpack (Type t, Stream strm) + { + throw new NotImplementedException (); + } + #endregion + + #region Compiled Packer Implementations + public abstract class PackerBase + { + Dictionary _packers = new Dictionary (); + Dictionary _unpackers = new Dictionary (); + + protected Dictionary _packMethods = new Dictionary (); + protected Dictionary _unpackMethods = new Dictionary (); + + protected PackerBase () + { + DefaultPackMethods.Register (_packMethods, _unpackMethods); + } + + public Action CreatePacker () + { + Delegate d; + lock (_packers) { + if (!_packers.TryGetValue (typeof (T), out d)) { + d = CreatePacker_Internal (); + _packers.Add (typeof (T), d); + } + } + return (Action)d; + } + + public Func CreateUnpacker () + { + Delegate d; + lock (_unpackers) { + if (!_unpackers.TryGetValue (typeof (T), out d)) { + d = CreateUnpacker_Internal (); + _unpackers.Add (typeof (T), d); + } + } + return (Func)d; + } + + protected abstract Action CreatePacker_Internal (); + protected abstract Func CreateUnpacker_Internal (); + } + public sealed class DynamicMethodPacker : PackerBase + { + protected static MethodInfo LookupMemberMappingMethod; + static Dictionary> UnpackMemberMappings; + + static DynamicMethodPacker () + { + UnpackMemberMappings = new Dictionary> (); + LookupMemberMappingMethod = typeof (DynamicMethodPacker).GetMethod ("LookupMemberMapping", BindingFlags.Static | BindingFlags.NonPublic); + } + + public DynamicMethodPacker () : base () + { + } + + protected override Action CreatePacker_Internal () + { + DynamicMethod dm = CreatePacker (typeof (T), CreatePackDynamicMethod (typeof (T))); + return (Action)dm.CreateDelegate (typeof (Action)); + } + + protected override Func CreateUnpacker_Internal () + { + DynamicMethod dm = CreateUnpacker (typeof (T), CreateUnpackDynamicMethod (typeof (T))); + return (Func)dm.CreateDelegate (typeof (Func)); + } + + DynamicMethod CreatePacker (Type t, DynamicMethod dm) + { + ILGenerator il = dm.GetILGenerator (); + _packMethods.Add (t, dm); + PackILGenerator.EmitPackCode (t, dm, il, LookupMembers, FormatMemberName, LookupPackMethod); + return dm; + } + + DynamicMethod CreateUnpacker (Type t, DynamicMethod dm) + { + ILGenerator il = dm.GetILGenerator (); + _unpackMethods.Add (t, dm); + PackILGenerator.EmitUnpackCode (t, dm, il, LookupMembers, FormatMemberName, LookupUnpackMethod, + LookupMemberMapping, LookupMemberMappingMethod); + return dm; + } + + static DynamicMethod CreatePackDynamicMethod (Type t) + { + return CreateDynamicMethod (typeof (void), new Type[] {typeof (MsgPackWriter), t}); + } + + static DynamicMethod CreateUnpackDynamicMethod (Type t) + { + return CreateDynamicMethod (t, new Type[] {typeof (MsgPackReader)}); + } + + static MemberInfo[] LookupMembers (Type t) + { + BindingFlags baseFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; + List list = new List (); + list.AddRange (t.GetFields (baseFlags)); + // TODO: Add NonSerialized Attribute Filter ? + return list.ToArray (); + } + + MethodInfo LookupPackMethod (Type t) + { + MethodInfo mi; + DynamicMethod dm; + if (_packMethods.TryGetValue (t, out mi)) + return mi; + dm = CreatePackDynamicMethod (t); + return CreatePacker (t, dm); + } + + MethodInfo LookupUnpackMethod (Type t) + { + MethodInfo mi; + if (_unpackMethods.TryGetValue (t, out mi)) + return mi; + DynamicMethod dm = CreateUnpackDynamicMethod (t); + return CreateUnpacker (t, dm); + } + + static string FormatMemberName (MemberInfo m) + { + if (m.MemberType != MemberTypes.Field) + return m.Name; + + int pos; + string name = m.Name; + if (name[0] == '<' && (pos = name.IndexOf ('>')) > 1) + name = name.Substring (1, pos - 1); // Auto-Property (\<.+\>) + return name; + } + + static int _dynamicMethodIdx = 0; + static DynamicMethod CreateDynamicMethod (Type returnType, Type[] parameterTypes) + { + string name = "_" + Interlocked.Increment (ref _dynamicMethodIdx).ToString (); + return new DynamicMethod (name, returnType, parameterTypes, true); + } + + internal static IDictionary LookupMemberMapping (Type t) + { + IDictionary mapping; + lock (UnpackMemberMappings) { + if (!UnpackMemberMappings.TryGetValue (t, out mapping)) { + mapping = new Dictionary (); + UnpackMemberMappings.Add (t, mapping); + } + } + return mapping; + } + } + public sealed class MethodBuilderPacker : PackerBase + { + public const string AssemblyName = "MessagePackInternalAssembly"; + static AssemblyName DynamicAsmName; + static AssemblyBuilder DynamicAsmBuilder; + static ModuleBuilder DynamicModuleBuilder; + + protected static MethodInfo LookupMemberMappingMethod; + static Dictionary> UnpackMemberMappings; + + static MethodBuilderPacker () + { + UnpackMemberMappings = new Dictionary> (); + LookupMemberMappingMethod = typeof (MethodBuilderPacker).GetMethod ("LookupMemberMapping", BindingFlags.Static | BindingFlags.NonPublic); + + DynamicAsmName = new AssemblyName (AssemblyName); + DynamicAsmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly (DynamicAsmName, AssemblyBuilderAccess.Run); + DynamicModuleBuilder = DynamicAsmBuilder.DefineDynamicModule (DynamicAsmName.Name); + } + + public MethodBuilderPacker () : base () + { + } + + protected override Action CreatePacker_Internal () + { + TypeBuilder tb; + MethodBuilder mb; + CreatePackMethodBuilder (typeof (T), out tb, out mb); + _packMethods.Add (typeof (T), mb); + CreatePacker (typeof (T), mb); + MethodInfo mi = ToCallableMethodInfo (typeof (T), tb, true); + return (Action)Delegate.CreateDelegate (typeof (Action), mi); + } + + protected override Func CreateUnpacker_Internal () + { + TypeBuilder tb; + MethodBuilder mb; + CreateUnpackMethodBuilder (typeof (T), out tb, out mb); + _unpackMethods.Add (typeof (T), mb); + CreateUnpacker (typeof (T), mb); + MethodInfo mi = ToCallableMethodInfo (typeof (T), tb, false); + return (Func)Delegate.CreateDelegate (typeof (Func), mi); + } + + void CreatePacker (Type t, MethodBuilder mb) + { + ILGenerator il = mb.GetILGenerator (); + PackILGenerator.EmitPackCode (t, mb, il, LookupMembers, FormatMemberName, LookupPackMethod); + } + + void CreateUnpacker (Type t, MethodBuilder mb) + { + ILGenerator il = mb.GetILGenerator (); + PackILGenerator.EmitUnpackCode (t, mb, il, LookupMembers, FormatMemberName, LookupUnpackMethod, + LookupMemberMapping, LookupMemberMappingMethod); + } + + MethodInfo ToCallableMethodInfo (Type t, TypeBuilder tb, bool isPacker) + { + Type type = tb.CreateType (); + MethodInfo mi = type.GetMethod (isPacker ? "Pack" : "Unpack", BindingFlags.Static | BindingFlags.Public); + if (isPacker) { + _packMethods[t] = mi; + } else { + _unpackMethods[t] = mi; + } + return mi; + } + + MethodInfo LookupPackMethod (Type t) + { + MethodInfo mi; + TypeBuilder tb; + MethodBuilder mb; + if (_packMethods.TryGetValue (t, out mi)) + return mi; + CreatePackMethodBuilder (t, out tb, out mb); + _packMethods.Add (t, mb); + CreatePacker (t, mb); + return ToCallableMethodInfo (t, tb, true); + } + + MethodInfo LookupUnpackMethod (Type t) + { + MethodInfo mi; + TypeBuilder tb; + MethodBuilder mb; + if (_unpackMethods.TryGetValue (t, out mi)) + return mi; + CreateUnpackMethodBuilder (t, out tb, out mb); + _unpackMethods.Add (t, mb); + CreateUnpacker (t, mb); + return ToCallableMethodInfo (t, tb, false); + } + + static string FormatMemberName (MemberInfo m) + { + return m.Name; + } + + static MemberInfo[] LookupMembers (Type t) + { + BindingFlags baseFlags = BindingFlags.Instance | BindingFlags.Public; + List list = new List (); + list.AddRange (t.GetFields (baseFlags)); + // TODO: Add NonSerialized Attribute Filter ? + return list.ToArray (); + } + + static void CreatePackMethodBuilder (Type t, out TypeBuilder tb, out MethodBuilder mb) + { + tb = DynamicModuleBuilder.DefineType (t.Name + "PackerType", TypeAttributes.Public); + mb = tb.DefineMethod ("Pack", MethodAttributes.Static | MethodAttributes.Public, typeof (void), new Type[] {typeof (MsgPackWriter), t}); + } + + static void CreateUnpackMethodBuilder (Type t, out TypeBuilder tb, out MethodBuilder mb) + { + tb = DynamicModuleBuilder.DefineType (t.Name + "UnpackerType", TypeAttributes.Public); + mb = tb.DefineMethod ("Unpack", MethodAttributes.Static | MethodAttributes.Public, t, new Type[] {typeof (MsgPackReader)}); + } + + internal static IDictionary LookupMemberMapping (Type t) + { + IDictionary mapping; + lock (UnpackMemberMappings) { + if (!UnpackMemberMappings.TryGetValue (t, out mapping)) { + mapping = new Dictionary (); + UnpackMemberMappings.Add (t, mapping); + } + } + return mapping; + } + } + #endregion + + #region default pack/unpack methods + internal static class DefaultPackMethods + { + public static void Register (Dictionary packMethods, Dictionary unpackMethods) + { + RegisterPackMethods (packMethods); + RegisterUnpackMethods (unpackMethods); + } + + #region Pack + static void RegisterPackMethods (Dictionary packMethods) + { + Type type = typeof (DefaultPackMethods); + MethodInfo[] methods = type.GetMethods (BindingFlags.Static | BindingFlags.NonPublic); + string methodName = "Pack"; + for (int i = 0; i < methods.Length; i ++) { + if (!methodName.Equals (methods[i].Name)) + continue; + ParameterInfo[] parameters = methods[i].GetParameters (); + if (parameters.Length != 2 || parameters[0].ParameterType != typeof (MsgPackWriter)) + continue; + packMethods.Add (parameters[1].ParameterType, methods[i]); + } + } + + internal static void Pack (MsgPackWriter writer, string x) + { + if (x == null) { + writer.WriteNil (); + } else { + writer.Write (x, false); + } + } + #endregion + + #region Unpack + static void RegisterUnpackMethods (Dictionary unpackMethods) + { + BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic; + Type type = typeof (DefaultPackMethods); + MethodInfo mi = type.GetMethod ("Unpack_Signed", flags); + unpackMethods.Add (typeof (sbyte), mi); + unpackMethods.Add (typeof (short), mi); + unpackMethods.Add (typeof (int), mi); + + mi = type.GetMethod ("Unpack_Signed64", flags); + unpackMethods.Add (typeof (long), mi); + + mi = type.GetMethod ("Unpack_Unsigned", flags); + unpackMethods.Add (typeof (byte), mi); + unpackMethods.Add (typeof (ushort), mi); + unpackMethods.Add (typeof (char), mi); + unpackMethods.Add (typeof (uint), mi); + + mi = type.GetMethod ("Unpack_Unsigned64", flags); + unpackMethods.Add (typeof (ulong), mi); + + mi = type.GetMethod ("Unpack_Boolean", flags); + unpackMethods.Add (typeof (bool), mi); + + mi = type.GetMethod ("Unpack_Float", flags); + unpackMethods.Add (typeof (float), mi); + + mi = type.GetMethod ("Unpack_Double", flags); + unpackMethods.Add (typeof (double), mi); + + mi = type.GetMethod ("Unpack_String", flags); + unpackMethods.Add (typeof (string), mi); + } + + internal static int Unpack_Signed (MsgPackReader reader) + { + if (!reader.Read () || !reader.IsSigned ()) + UnpackFailed (); + return reader.ValueSigned; + } + + internal static long Unpack_Signed64 (MsgPackReader reader) + { + if (!reader.Read ()) + UnpackFailed (); + if (reader.IsSigned ()) + return reader.ValueSigned; + if (reader.IsSigned64 ()) + return reader.ValueSigned64; + UnpackFailed (); + return 0; // unused + } + + internal static uint Unpack_Unsigned (MsgPackReader reader) + { + if (!reader.Read () || !reader.IsUnsigned ()) + UnpackFailed (); + return reader.ValueUnsigned; + } + + internal static ulong Unpack_Unsigned64 (MsgPackReader reader) + { + if (!reader.Read ()) + UnpackFailed (); + if (reader.IsUnsigned ()) + return reader.ValueUnsigned; + if (reader.IsUnsigned64 ()) + return reader.ValueUnsigned64; + UnpackFailed (); + return 0; // unused + } + + internal static bool Unpack_Boolean (MsgPackReader reader) + { + if (!reader.Read () || !reader.IsBoolean ()) + UnpackFailed (); + return reader.ValueBoolean; + } + + internal static float Unpack_Float (MsgPackReader reader) + { + if (!reader.Read () || reader.Type != TypePrefixes.Float) + UnpackFailed (); + return reader.ValueFloat; + } + + internal static double Unpack_Double (MsgPackReader reader) + { + if (!reader.Read () || reader.Type != TypePrefixes.Double) + UnpackFailed (); + return reader.ValueDouble; + } + + internal static string Unpack_String (MsgPackReader reader) + { + if (!reader.Read () || !reader.IsRaw ()) + UnpackFailed (); + return reader.ReadRawString (); + } + + internal static void UnpackFailed () + { + throw new FormatException (); + } + #endregion + } + #endregion + } +} diff --git a/csharp/MsgPack/Compiler/EmitExtensions.cs b/csharp/MsgPack/Compiler/EmitExtensions.cs new file mode 100644 index 00000000..794aff4f --- /dev/null +++ b/csharp/MsgPack/Compiler/EmitExtensions.cs @@ -0,0 +1,191 @@ +// +// Copyright 2011 Kazuki Oikawa +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Reflection; +using System.Reflection.Emit; + +namespace MsgPack.Compiler +{ + public static class EmitExtensions + { + public static void EmitLd (this ILGenerator il, Variable v) + { + switch (v.VarType) { + case VariableType.Arg: + EmitLdarg (il, v); + break; + case VariableType.Local: + EmitLdloc (il, v); + break; + default: + throw new ArgumentException (); + } + } + + public static void EmitLd (this ILGenerator il, params Variable[] list) + { + for (int i = 0; i < list.Length; i ++) + EmitLd (il, list[i]); + } + + public static void EmitLdarg (this ILGenerator il, Variable v) + { + if (v.VarType != VariableType.Arg) + throw new ArgumentException (); + + switch (v.Index) { + case 0: il.Emit (OpCodes.Ldarg_0); return; + case 1: il.Emit (OpCodes.Ldarg_1); return; + case 2: il.Emit (OpCodes.Ldarg_2); return; + case 3: il.Emit (OpCodes.Ldarg_3); return; + } + if (v.Index <= byte.MaxValue) { + il.Emit (OpCodes.Ldarg_S, (byte)v.Index); + } else if (v.Index <= short.MaxValue) { + il.Emit (OpCodes.Ldarg, v.Index); + } else { + throw new FormatException (); + } + } + + public static void EmitLdloc (this ILGenerator il, Variable v) + { + if (v.VarType != VariableType.Local) + throw new ArgumentException (); + + switch (v.Index) { + case 0: il.Emit (OpCodes.Ldloc_0); return; + case 1: il.Emit (OpCodes.Ldloc_1); return; + case 2: il.Emit (OpCodes.Ldloc_2); return; + case 3: il.Emit (OpCodes.Ldloc_3); return; + } + if (v.Index <= byte.MaxValue) { + il.Emit (OpCodes.Ldloc_S, (byte)v.Index); + } else if (v.Index <= short.MaxValue) { + il.Emit (OpCodes.Ldloc, v.Index); + } else { + throw new FormatException (); + } + } + + public static void EmitSt (this ILGenerator il, Variable v) + { + switch (v.VarType) { + case VariableType.Arg: + EmitStarg (il, v); + break; + case VariableType.Local: + EmitStloc (il, v); + break; + default: + throw new ArgumentException (); + } + } + + public static void EmitStarg (this ILGenerator il, Variable v) + { + if (v.VarType != VariableType.Arg) + throw new ArgumentException (); + + if (v.Index <= byte.MaxValue) { + il.Emit (OpCodes.Starg_S, (byte)v.Index); + } else if (v.Index <= short.MaxValue) { + il.Emit (OpCodes.Starg, v.Index); + } else { + throw new FormatException (); + } + } + + public static void EmitStloc (this ILGenerator il, Variable v) + { + if (v.VarType != VariableType.Local) + throw new ArgumentException (); + + switch (v.Index) { + case 0: il.Emit (OpCodes.Stloc_0); return; + case 1: il.Emit (OpCodes.Stloc_1); return; + case 2: il.Emit (OpCodes.Stloc_2); return; + case 3: il.Emit (OpCodes.Stloc_3); return; + } + if (v.Index <= byte.MaxValue) { + il.Emit (OpCodes.Stloc_S, (byte)v.Index); + } else if (v.Index <= short.MaxValue) { + il.Emit (OpCodes.Stloc, v.Index); + } else { + throw new FormatException (); + } + } + + public static void EmitLdc (this ILGenerator il, int v) + { + switch (v) { + case 0: il.Emit (OpCodes.Ldc_I4_0); return; + case 1: il.Emit (OpCodes.Ldc_I4_1); return; + case 2: il.Emit (OpCodes.Ldc_I4_2); return; + case 3: il.Emit (OpCodes.Ldc_I4_3); return; + case 4: il.Emit (OpCodes.Ldc_I4_4); return; + case 5: il.Emit (OpCodes.Ldc_I4_5); return; + case 6: il.Emit (OpCodes.Ldc_I4_6); return; + case 7: il.Emit (OpCodes.Ldc_I4_7); return; + case 8: il.Emit (OpCodes.Ldc_I4_8); return; + case -1: il.Emit (OpCodes.Ldc_I4_M1); return; + } + if (v <= sbyte.MaxValue && v >= sbyte.MinValue) { + il.Emit (OpCodes.Ldc_I4_S, (sbyte)v); + } else { + il.Emit (OpCodes.Ldc_I4, v); + } + } + + public static void EmitLd_False (this ILGenerator il) + { + il.Emit (OpCodes.Ldc_I4_1); + } + + public static void EmitLd_True (this ILGenerator il) + { + il.Emit (OpCodes.Ldc_I4_1); + } + + public static void EmitLdstr (this ILGenerator il, string v) + { + il.Emit (OpCodes.Ldstr, v); + } + + public static void EmitLdMember (this ILGenerator il, MemberInfo m) + { + if (m.MemberType == MemberTypes.Field) { + il.Emit (OpCodes.Ldfld, (FieldInfo)m); + } else if (m.MemberType == MemberTypes.Property) { + il.Emit (OpCodes.Callvirt, ((PropertyInfo)m).GetGetMethod (true)); + } else { + throw new ArgumentException (); + } + } + + public static void EmitStMember (this ILGenerator il, MemberInfo m) + { + if (m.MemberType == MemberTypes.Field) { + il.Emit (OpCodes.Stfld, (FieldInfo)m); + } else if (m.MemberType == MemberTypes.Property) { + il.Emit (OpCodes.Callvirt, ((PropertyInfo)m).GetSetMethod (true)); + } else { + throw new ArgumentException (); + } + } + } +} diff --git a/csharp/MsgPack/Compiler/PackILGenerator.cs b/csharp/MsgPack/Compiler/PackILGenerator.cs new file mode 100644 index 00000000..1f116ad7 --- /dev/null +++ b/csharp/MsgPack/Compiler/PackILGenerator.cs @@ -0,0 +1,386 @@ +// +// Copyright 2011 Kazuki Oikawa +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.Serialization; + +namespace MsgPack.Compiler +{ + static class PackILGenerator + { + #region Pack IL Generator + public static void EmitPackCode (Type type, MethodInfo mi, ILGenerator il, + Func targetMemberSelector, + Func memberNameFormatter, + Func lookupPackMethod) + { + if (type.IsPrimitive || type.IsInterface) + throw new NotSupportedException (); + + Variable arg_writer = Variable.CreateArg (0); + Variable arg_obj = Variable.CreateArg (1); + Variable local_i = Variable.CreateLocal (il.DeclareLocal (typeof (int))); + + if (!type.IsValueType) { // null check + Label notNullLabel = il.DefineLabel (); + il.EmitLd (arg_obj); + il.Emit (OpCodes.Brtrue_S, notNullLabel); + il.EmitLd (arg_writer); + il.Emit (OpCodes.Call, typeof(MsgPackWriter).GetMethod("WriteNil", new Type[0])); + il.Emit (OpCodes.Ret); + il.MarkLabel (notNullLabel); + } + + if (type.IsArray) { + EmitPackArrayCode (mi, il, type, arg_writer, arg_obj, local_i, lookupPackMethod); + goto FinallyProcess; + } + + // MsgPackWriter.WriteMapHeader + MemberInfo[] members = targetMemberSelector (type); + il.EmitLd (arg_writer); + il.EmitLdc (members.Length); + il.Emit (OpCodes.Callvirt, typeof (MsgPackWriter).GetMethod("WriteMapHeader", new Type[]{typeof (int)})); + + for (int i = 0; i < members.Length; i ++) { + MemberInfo m = members[i]; + Type mt = m.GetMemberType (); + + // write field-name + il.EmitLd (arg_writer); + il.EmitLdstr (memberNameFormatter (m)); + il.EmitLd_True (); + il.Emit (OpCodes.Call, typeof (MsgPackWriter).GetMethod("Write", new Type[]{typeof (string), typeof (bool)})); + + // write value + EmitPackMemberValueCode (mt, il, arg_writer, arg_obj, m, null, type, mi, lookupPackMethod); + } + +FinallyProcess: + il.Emit (OpCodes.Ret); + } + + static void EmitPackArrayCode (MethodInfo mi, ILGenerator il, Type t, Variable var_writer, Variable var_obj, Variable var_loop, Func lookupPackMethod) + { + Type et = t.GetElementType (); + il.EmitLd (var_writer, var_obj); + il.Emit (OpCodes.Ldlen); + il.Emit (OpCodes.Call, typeof(MsgPackWriter).GetMethod("WriteArrayHeader", new Type[]{ typeof(int) })); + + Label beginLabel = il.DefineLabel (); + Label exprLabel = il.DefineLabel (); + + // for-loop: init loop counter + il.EmitLdc (0); + il.EmitSt (var_loop); + + // jump + il.Emit (OpCodes.Br_S, exprLabel); + + // mark begin-label + il.MarkLabel (beginLabel); + + // write element + EmitPackMemberValueCode (et, il, var_writer, var_obj, null, var_loop, t, mi, lookupPackMethod); + + // increment loop-counter + il.EmitLd (var_loop); + il.Emit (OpCodes.Ldc_I4_1); + il.Emit (OpCodes.Add); + il.EmitSt (var_loop); + + // mark expression label + il.MarkLabel (exprLabel); + + // expression + il.EmitLd (var_loop, var_obj); + il.Emit (OpCodes.Ldlen); + il.Emit (OpCodes.Blt_S, beginLabel); + } + + /// (optional) + /// (optional) + static void EmitPackMemberValueCode (Type type, ILGenerator il, Variable var_writer, Variable var_obj, + MemberInfo m, Variable elementIdx, Type currentType, MethodInfo currentMethod, Func lookupPackMethod) + { + MethodInfo mi; + il.EmitLd (var_writer, var_obj); + if (m != null) + il.EmitLdMember (m); + if (elementIdx != null) { + il.EmitLd (elementIdx); + il.Emit (OpCodes.Ldelem, type); + } + if (type.IsPrimitive) { + mi = typeof(MsgPackWriter).GetMethod("Write", new Type[]{type}); + } else { + if (currentType == type) { + mi = currentMethod; + } else { + mi = lookupPackMethod (type); + } + } + il.Emit (OpCodes.Call, mi); + } + #endregion + + #region Unpack IL Generator + public static void EmitUnpackCode (Type type, MethodInfo mi, ILGenerator il, + Func targetMemberSelector, + Func memberNameFormatter, + Func lookupUnpackMethod, + Func> lookupMemberMapping, + MethodInfo lookupMemberMappingMethod) + { + if (type.IsArray) { + EmitUnpackArrayCode (type, mi, il, targetMemberSelector, memberNameFormatter, lookupUnpackMethod); + } else { + EmitUnpackMapCode (type, mi, il, targetMemberSelector, memberNameFormatter, lookupUnpackMethod, lookupMemberMapping, lookupMemberMappingMethod); + } + } + + static void EmitUnpackMapCode (Type type, MethodInfo mi, ILGenerator il, + Func targetMemberSelector, + Func memberNameFormatter, + Func lookupUnpackMethod, + Func> lookupMemberMapping, + MethodInfo lookupMemberMappingMethod) + { + MethodInfo failedMethod = typeof (PackILGenerator).GetMethod ("UnpackFailed", BindingFlags.Static | BindingFlags.NonPublic); + MemberInfo[] members = targetMemberSelector (type); + IDictionary member_mapping = lookupMemberMapping (type); + for (int i = 0; i < members.Length; i ++) + member_mapping.Add (memberNameFormatter (members[i]), i); + + Variable msgpackReader = Variable.CreateArg (0); + Variable obj = Variable.CreateLocal (il.DeclareLocal (type)); + Variable num_of_fields = Variable.CreateLocal (il.DeclareLocal (typeof (int))); + Variable loop_idx = Variable.CreateLocal (il.DeclareLocal (typeof (int))); + Variable mapping = Variable.CreateLocal (il.DeclareLocal (typeof (IDictionary))); + Variable switch_idx = Variable.CreateLocal (il.DeclareLocal (typeof (int))); + Variable var_type = Variable.CreateLocal (il.DeclareLocal (typeof (Type))); + + // if (!MsgPackReader.Read()) UnpackFailed (); + // if (MsgPackReader.Type == TypePrefixes.Nil) return null; + // if (!MsgPackReader.IsMap ()) UnpackFailed (); + EmitUnpackReadAndTypeCheckCode (il, msgpackReader, typeof (MsgPackReader).GetMethod ("IsMap"), failedMethod, true); + + // type = typeof (T) + il.Emit (OpCodes.Ldtoken, type); + il.Emit (OpCodes.Call, typeof(Type).GetMethod ("GetTypeFromHandle")); + il.EmitSt (var_type); + + // mapping = LookupMemberMapping (typeof (T)) + il.EmitLd (var_type); + il.Emit (OpCodes.Call, lookupMemberMappingMethod); + il.EmitSt (mapping); + + // object o = FormatterServices.GetUninitializedObject (Type); + il.EmitLd (var_type); + il.Emit (OpCodes.Call, typeof (FormatterServices).GetMethod ("GetUninitializedObject")); + il.Emit (OpCodes.Castclass, type); + il.EmitSt (obj); + + // num_of_fields = (int)reader.Length + il.EmitLd (msgpackReader); + il.Emit (OpCodes.Call, typeof (MsgPackReader).GetProperty ("Length").GetGetMethod ()); + il.EmitSt (num_of_fields); + + // Loop labels + Label lblLoopStart = il.DefineLabel (); + Label lblLoopExpr = il.DefineLabel (); + + // i = 0; + il.EmitLdc (0); + il.EmitSt (loop_idx); + il.Emit (OpCodes.Br, lblLoopExpr); + il.MarkLabel (lblLoopStart); + + /* process */ + // if (!MsgPackReader.Read() || !MsgPackReader.IsRaw()) UnpackFailed(); + EmitUnpackReadAndTypeCheckCode (il, msgpackReader, typeof (MsgPackReader).GetMethod ("IsRaw"), failedMethod, false); + + // MsgPackReader.ReadRawString () + // if (!Dictionary.TryGetValue (,)) UnpackFailed(); + Label lbl3 = il.DefineLabel (); + il.EmitLd (mapping); + il.EmitLd (msgpackReader); + il.Emit (OpCodes.Call, typeof (MsgPackReader).GetMethod ("ReadRawString", new Type[0])); + il.Emit (OpCodes.Ldloca_S, (byte)switch_idx.Index); + il.Emit (OpCodes.Callvirt, typeof (IDictionary).GetMethod ("TryGetValue")); + il.Emit (OpCodes.Brtrue, lbl3); + il.Emit (OpCodes.Call, failedMethod); + il.MarkLabel (lbl3); + + // switch + Label[] switchCases = new Label[members.Length]; + for (int i = 0; i < switchCases.Length; i ++) + switchCases[i] = il.DefineLabel (); + Label switchCaseEndLabel = il.DefineLabel (); + il.EmitLd (switch_idx); + il.Emit (OpCodes.Switch, switchCases); + il.Emit (OpCodes.Call, failedMethod); + + for (int i = 0; i < switchCases.Length; i ++) { + il.MarkLabel (switchCases[i]); + MemberInfo minfo = members[i]; + Type mt = minfo.GetMemberType (); + MethodInfo unpack_method = lookupUnpackMethod (mt); + il.EmitLd (obj); + il.EmitLd (msgpackReader); + il.Emit (OpCodes.Call, unpack_method); + il.EmitStMember (minfo); + il.Emit (OpCodes.Br, switchCaseEndLabel); + } + il.MarkLabel (switchCaseEndLabel); + + // i ++ + il.EmitLd (loop_idx); + il.EmitLdc (1); + il.Emit (OpCodes.Add); + il.EmitSt (loop_idx); + + // i < num_of_fields; + il.MarkLabel (lblLoopExpr); + il.EmitLd (loop_idx); + il.EmitLd (num_of_fields); + il.Emit (OpCodes.Blt, lblLoopStart); + + // return + il.EmitLd (obj); + il.Emit (OpCodes.Ret); + } + + static void EmitUnpackArrayCode (Type arrayType, MethodInfo mi, ILGenerator il, + Func targetMemberSelector, + Func memberNameFormatter, + Func lookupUnpackMethod) + { + Type elementType = arrayType.GetElementType (); + MethodInfo failedMethod = typeof (PackILGenerator).GetMethod ("UnpackFailed", BindingFlags.Static | BindingFlags.NonPublic); + + Variable msgpackReader = Variable.CreateArg (0); + Variable obj = Variable.CreateLocal (il.DeclareLocal (arrayType)); + Variable num_of_elements = Variable.CreateLocal (il.DeclareLocal (typeof (int))); + Variable loop_idx = Variable.CreateLocal (il.DeclareLocal (typeof (int))); + Variable type = Variable.CreateLocal (il.DeclareLocal (typeof (Type))); + + // if (!MsgPackReader.Read() || !MsgPackReader.IsArray ()) UnpackFailed (); + EmitUnpackReadAndTypeCheckCode (il, msgpackReader, typeof (MsgPackReader).GetMethod ("IsArray"), failedMethod, true); + + // type = typeof (T) + il.Emit (OpCodes.Ldtoken, elementType); + il.Emit (OpCodes.Call, typeof(Type).GetMethod ("GetTypeFromHandle")); + il.EmitSt (type); + + // num_of_elements = (int)reader.Length + il.EmitLd (msgpackReader); + il.Emit (OpCodes.Call, typeof (MsgPackReader).GetProperty ("Length").GetGetMethod ()); + il.EmitSt (num_of_elements); + + // object o = Array.CreateInstance (Type, Length); + il.EmitLd (type); + il.EmitLd (num_of_elements); + il.Emit (OpCodes.Call, typeof (Array).GetMethod ("CreateInstance", new Type[] {typeof (Type), typeof (int)})); + il.Emit (OpCodes.Castclass, arrayType); + il.EmitSt (obj); + + // Unpack element method + MethodInfo unpack_method = lookupUnpackMethod (elementType); + + // Loop labels + Label lblLoopStart = il.DefineLabel (); + Label lblLoopExpr = il.DefineLabel (); + + // i = 0; + il.EmitLdc (0); + il.EmitSt (loop_idx); + il.Emit (OpCodes.Br, lblLoopExpr); + il.MarkLabel (lblLoopStart); + + /* process */ + il.EmitLd (obj, loop_idx); + il.EmitLd (msgpackReader); + il.Emit (OpCodes.Call, unpack_method); + il.Emit (OpCodes.Stelem, elementType); + + // i ++ + il.EmitLd (loop_idx); + il.EmitLdc (1); + il.Emit (OpCodes.Add); + il.EmitSt (loop_idx); + + // i < num_of_fields; + il.MarkLabel (lblLoopExpr); + il.EmitLd (loop_idx); + il.EmitLd (num_of_elements); + il.Emit (OpCodes.Blt, lblLoopStart); + + // return + il.EmitLd (obj); + il.Emit (OpCodes.Ret); + } + + static void EmitUnpackReadAndTypeCheckCode (ILGenerator il, Variable msgpackReader, MethodInfo typeCheckMethod, MethodInfo failedMethod, bool nullCheckAndReturn) + { + Label lblFailed = il.DefineLabel (); + Label lblNullReturn = nullCheckAndReturn ? il.DefineLabel () : default(Label); + Label lblPassed = il.DefineLabel (); + il.EmitLd (msgpackReader); + il.Emit (OpCodes.Call, typeof (MsgPackReader).GetMethod ("Read")); + il.Emit (OpCodes.Brfalse_S, lblFailed); + if (nullCheckAndReturn) { + il.EmitLd (msgpackReader); + il.Emit (OpCodes.Call, typeof (MsgPackReader).GetProperty ("Type").GetGetMethod ()); + il.EmitLdc ((int)TypePrefixes.Nil); + il.Emit (OpCodes.Beq_S, lblNullReturn); + } + il.EmitLd (msgpackReader); + il.Emit (OpCodes.Call, typeCheckMethod); + il.Emit (OpCodes.Brtrue_S, lblPassed); + il.Emit (OpCodes.Br, lblFailed); + if (nullCheckAndReturn) { + il.MarkLabel (lblNullReturn); + il.Emit (OpCodes.Ldnull); + il.Emit (OpCodes.Ret); + } + il.MarkLabel (lblFailed); + il.Emit (OpCodes.Call, failedMethod); + il.MarkLabel (lblPassed); + } + + /// Exception Helper + internal static void UnpackFailed () + { + throw new FormatException (); + } + #endregion + + #region Misc + static Type GetMemberType (this MemberInfo mi) + { + if (mi.MemberType == MemberTypes.Field) + return ((FieldInfo)mi).FieldType; + if (mi.MemberType == MemberTypes.Property) + return ((PropertyInfo)mi).PropertyType; + throw new ArgumentException (); + } + #endregion + } +} diff --git a/csharp/MsgPack/Compiler/Variable.cs b/csharp/MsgPack/Compiler/Variable.cs new file mode 100644 index 00000000..00c8e51c --- /dev/null +++ b/csharp/MsgPack/Compiler/Variable.cs @@ -0,0 +1,42 @@ +// +// Copyright 2011 Kazuki Oikawa +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System.Reflection.Emit; + +namespace MsgPack.Compiler +{ + public class Variable + { + Variable (VariableType type, int index) + { + this.VarType = type; + this.Index = index; + } + + public static Variable CreateLocal (LocalBuilder local) + { + return new Variable (VariableType.Local, local.LocalIndex); + } + + public static Variable CreateArg (int idx) + { + return new Variable (VariableType.Arg, idx); + } + + public VariableType VarType { get; set; } + public int Index { get; set; } + } +} diff --git a/csharp/MsgPack/Compiler/VariableType.cs b/csharp/MsgPack/Compiler/VariableType.cs new file mode 100644 index 00000000..306b516b --- /dev/null +++ b/csharp/MsgPack/Compiler/VariableType.cs @@ -0,0 +1,24 @@ +// +// Copyright 2011 Kazuki Oikawa +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace MsgPack.Compiler +{ + public enum VariableType + { + Local, + Arg + } +} diff --git a/csharp/MsgPack/MsgPack.csproj b/csharp/MsgPack/MsgPack.csproj new file mode 100644 index 00000000..9a8d13de --- /dev/null +++ b/csharp/MsgPack/MsgPack.csproj @@ -0,0 +1,63 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {E1809531-EC2A-4EA6-B0E8-CC815EDFAA2F} + Library + Properties + MsgPack + MsgPack + v4.0 + 512 + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + true + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/csharp/MsgPack/MsgPackReader.cs b/csharp/MsgPack/MsgPackReader.cs new file mode 100644 index 00000000..3338a53b --- /dev/null +++ b/csharp/MsgPack/MsgPackReader.cs @@ -0,0 +1,258 @@ +// +// Copyright 2011 Kazuki Oikawa +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.IO; +using System.Text; + +namespace MsgPack +{ + public class MsgPackReader + { + Stream _strm; + byte[] _tmp0 = new byte[8]; + byte[] _tmp1 = new byte[8]; + + Encoding _encoding = Encoding.UTF8; + Decoder _decoder = Encoding.UTF8.GetDecoder (); + byte[] _buf = new byte[64]; + + public MsgPackReader (Stream strm) + { + _strm = strm; + } + + public TypePrefixes Type { get; private set; } + + public bool ValueBoolean { get; private set; } + public uint Length { get; private set; } + + public uint ValueUnsigned { get; private set; } + public ulong ValueUnsigned64 { get; private set; } + + public int ValueSigned { get; private set; } + public long ValueSigned64 { get; private set; } + + public float ValueFloat { get; private set; } + public double ValueDouble { get; private set; } + + public bool IsSigned () + { + return this.Type == TypePrefixes.NegativeFixNum || + this.Type == TypePrefixes.PositiveFixNum || + this.Type == TypePrefixes.Int8 || + this.Type == TypePrefixes.Int16 || + this.Type == TypePrefixes.Int32; + } + + public bool IsBoolean () + { + return this.Type == TypePrefixes.True || this.Type == TypePrefixes.False; + } + + public bool IsSigned64 () + { + return this.Type == TypePrefixes.Int64; + } + + public bool IsUnsigned () + { + return this.Type == TypePrefixes.PositiveFixNum || + this.Type == TypePrefixes.UInt8 || + this.Type == TypePrefixes.UInt16 || + this.Type == TypePrefixes.UInt32; + } + + public bool IsUnsigned64 () + { + return this.Type == TypePrefixes.UInt64; + } + + public bool IsRaw () + { + return this.Type == TypePrefixes.FixRaw || this.Type == TypePrefixes.Raw16 || this.Type == TypePrefixes.Raw32; + } + + public bool IsArray () + { + return this.Type == TypePrefixes.FixArray || this.Type == TypePrefixes.Array16 || this.Type == TypePrefixes.Array32; + } + + public bool IsMap () + { + return this.Type == TypePrefixes.FixMap || this.Type == TypePrefixes.Map16 || this.Type == TypePrefixes.Map32; + } + + public bool Read () + { + byte[] tmp0 = _tmp0, tmp1 = _tmp1; + int x = _strm.ReadByte (); + if (x < 0) + return false; // EOS + + if (x >= 0x00 && x <= 0x7f) { + this.Type = TypePrefixes.PositiveFixNum; + } else if (x >= 0xe0 && x <= 0xff) { + this.Type = TypePrefixes.NegativeFixNum; + } else if (x >= 0xa0 && x <= 0xbf) { + this.Type = TypePrefixes.FixRaw; + } else if (x >= 0x90 && x <= 0x9f) { + this.Type = TypePrefixes.FixArray; + } else if (x >= 0x80 && x <= 0x8f) { + this.Type = TypePrefixes.FixMap; + } else { + this.Type = (TypePrefixes)x; + } + + switch (this.Type) { + case TypePrefixes.Nil: + break; + case TypePrefixes.False: + ValueBoolean = false; + break; + case TypePrefixes.True: + ValueBoolean = true; + break; + case TypePrefixes.Float: + _strm.Read (tmp0, 0, 4); + if (BitConverter.IsLittleEndian) { + tmp1[0] = tmp0[3]; + tmp1[1] = tmp0[2]; + tmp1[2] = tmp0[1]; + tmp1[3] = tmp0[0]; + ValueFloat = BitConverter.ToSingle (tmp1, 0); + } else { + ValueFloat = BitConverter.ToSingle (tmp0, 0); + } + break; + case TypePrefixes.Double: + _strm.Read (tmp0, 0, 8); + if (BitConverter.IsLittleEndian) { + tmp1[0] = tmp0[7]; + tmp1[1] = tmp0[6]; + tmp1[2] = tmp0[5]; + tmp1[3] = tmp0[4]; + tmp1[4] = tmp0[3]; + tmp1[5] = tmp0[2]; + tmp1[6] = tmp0[1]; + tmp1[7] = tmp0[0]; + ValueDouble = BitConverter.ToDouble (tmp1, 0); + } else { + ValueDouble = BitConverter.ToDouble (tmp0, 0); + } + break; + case TypePrefixes.NegativeFixNum: + ValueSigned = (x & 0x1f) - 0x20; + break; + case TypePrefixes.PositiveFixNum: + ValueSigned = x & 0x7f; + ValueUnsigned = (uint)ValueSigned; + break; + case TypePrefixes.UInt8: + x = _strm.ReadByte (); + if (x < 0) + throw new FormatException (); + ValueUnsigned = (uint)x; + break; + case TypePrefixes.UInt16: + if (_strm.Read (tmp0, 0, 2) != 2) + throw new FormatException (); + ValueUnsigned = ((uint)tmp0[0] << 8) | (uint)tmp0[1]; + break; + case TypePrefixes.UInt32: + if (_strm.Read (tmp0, 0, 4) != 4) + throw new FormatException (); + ValueUnsigned = ((uint)tmp0[0] << 24) | ((uint)tmp0[1] << 16) | ((uint)tmp0[2] << 8) | (uint)tmp0[3]; + break; + case TypePrefixes.UInt64: + if (_strm.Read (tmp0, 0, 8) != 8) + throw new FormatException (); + ValueUnsigned64 = ((ulong)tmp0[0] << 56) | ((ulong)tmp0[1] << 48) | ((ulong)tmp0[2] << 40) | ((ulong)tmp0[3] << 32) | ((ulong)tmp0[4] << 24) | ((ulong)tmp0[5] << 16) | ((ulong)tmp0[6] << 8) | (ulong)tmp0[7]; + break; + case TypePrefixes.Int8: + x = _strm.ReadByte (); + if (x < 0) + throw new FormatException (); + ValueSigned = (sbyte)x; + break; + case TypePrefixes.Int16: + if (_strm.Read (tmp0, 0, 2) != 2) + throw new FormatException (); + ValueSigned = (short)((tmp0[0] << 8) | tmp0[1]); + break; + case TypePrefixes.Int32: + if (_strm.Read (tmp0, 0, 4) != 4) + throw new FormatException (); + ValueSigned = (tmp0[0] << 24) | (tmp0[1] << 16) | (tmp0[2] << 8) | tmp0[3]; + break; + case TypePrefixes.Int64: + if (_strm.Read (tmp0, 0, 8) != 8) + throw new FormatException (); + ValueSigned64 = ((long)tmp0[0] << 56) | ((long)tmp0[1] << 48) | ((long)tmp0[2] << 40) | ((long)tmp0[3] << 32) | ((long)tmp0[4] << 24) | ((long)tmp0[5] << 16) | ((long)tmp0[6] << 8) | (long)tmp0[7]; + break; + case TypePrefixes.FixRaw: + Length = (uint)(x & 0x1f); + break; + case TypePrefixes.FixArray: + case TypePrefixes.FixMap: + Length = (uint)(x & 0xf); + break; + case TypePrefixes.Raw16: + case TypePrefixes.Array16: + case TypePrefixes.Map16: + if (_strm.Read (tmp0, 0, 2) != 2) + throw new FormatException (); + Length = ((uint)tmp0[0] << 8) | (uint)tmp0[1]; + break; + case TypePrefixes.Raw32: + case TypePrefixes.Array32: + case TypePrefixes.Map32: + if (_strm.Read (tmp0, 0, 4) != 4) + throw new FormatException (); + Length = ((uint)tmp0[0] << 24) | ((uint)tmp0[1] << 16) | ((uint)tmp0[2] << 8) | (uint)tmp0[3]; + break; + default: + throw new FormatException (); + } + return true; + } + + public int ReadValueRaw (byte[] buf, int offset, int count) + { + return _strm.Read (buf, offset, count); + } + + public string ReadRawString () + { + return ReadRawString (_buf); + } + + public unsafe string ReadRawString (byte[] buf) + { + if (this.Length < buf.Length) { + if (ReadValueRaw (buf, 0, (int)this.Length) != this.Length) + throw new FormatException (); + return _encoding.GetString (buf, 0, (int)this.Length); + } + + // Poor implementation + byte[] tmp = new byte[(int)this.Length]; + if (ReadValueRaw (tmp, 0, tmp.Length) != tmp.Length) + throw new FormatException (); + return _encoding.GetString (tmp); + } + } +} diff --git a/csharp/MsgPack/MsgPackWriter.cs b/csharp/MsgPack/MsgPackWriter.cs new file mode 100644 index 00000000..39647d87 --- /dev/null +++ b/csharp/MsgPack/MsgPackWriter.cs @@ -0,0 +1,315 @@ +// +// Copyright 2011 Kazuki Oikawa +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.IO; +using System.Text; + +namespace MsgPack +{ + public class MsgPackWriter + { + Stream _strm; + Encoding _encoding = Encoding.UTF8; + Encoder _encoder = Encoding.UTF8.GetEncoder (); + byte[] _tmp = new byte[9]; + byte[] _buf = new byte[64]; + + public MsgPackWriter (Stream strm) + { + _strm = strm; + } + + public void Write (byte x) + { + if (x < 128) { + _strm.WriteByte (x); + } else { + byte[] tmp = _tmp; + tmp[0] = 0xcc; + tmp[1] = x; + _strm.Write (tmp, 0, 2); + } + } + + public void Write (ushort x) + { + if (x < 0x100) { + Write ((byte)x); + } else { + byte[] tmp = _tmp; + tmp[0] = 0xcd; + tmp[1] = (byte)(x >> 8); + tmp[2] = (byte)x; + _strm.Write (tmp, 0, 3); + } + } + + public void Write (char x) + { + Write ((ushort)x); + } + + public void Write (uint x) + { + if (x < 0x10000) { + Write ((ushort)x); + } else { + byte[] tmp = _tmp; + tmp[0] = 0xce; + tmp[1] = (byte)(x >> 24); + tmp[2] = (byte)(x >> 16); + tmp[3] = (byte)(x >> 8); + tmp[4] = (byte)x; + _strm.Write (tmp, 0, 5); + } + } + + public void Write (ulong x) + { + if (x < 0x100000000) { + Write ((uint)x); + } else { + byte[] tmp = _tmp; + tmp[0] = 0xcf; + tmp[1] = (byte)(x >> 56); + tmp[2] = (byte)(x >> 48); + tmp[3] = (byte)(x >> 40); + tmp[4] = (byte)(x >> 32); + tmp[5] = (byte)(x >> 24); + tmp[6] = (byte)(x >> 16); + tmp[7] = (byte)(x >> 8); + tmp[8] = (byte)x; + _strm.Write (tmp, 0, 9); + } + } + + public void Write (sbyte x) + { + if (x >= -32 && x <= -1) { + _strm.WriteByte ((byte)(0xe0 | (byte)x)); + } else if (x >= 0 && x <= 127) { + _strm.WriteByte ((byte)x); + } else { + byte[] tmp = _tmp; + tmp[0] = 0xd0; + tmp[1] = (byte)x; + _strm.Write (tmp, 0, 2); + } + } + + public void Write (short x) + { + if (x >= sbyte.MinValue && x <= sbyte.MaxValue) { + Write ((sbyte)x); + } else { + byte[] tmp = _tmp; + tmp[0] = 0xd1; + tmp[1] = (byte)(x >> 8); + tmp[2] = (byte)x; + _strm.Write (tmp, 0, 3); + } + } + + public void Write (int x) + { + if (x >= short.MinValue && x <= short.MaxValue) { + Write ((short)x); + } else { + byte[] tmp = _tmp; + tmp[0] = 0xd2; + tmp[1] = (byte)(x >> 24); + tmp[2] = (byte)(x >> 16); + tmp[3] = (byte)(x >> 8); + tmp[4] = (byte)x; + _strm.Write (tmp, 0, 5); + } + } + + public void Write (long x) + { + if (x >= int.MinValue && x <= int.MaxValue) { + Write ((int)x); + } else { + byte[] tmp = _tmp; + tmp[0] = 0xd3; + tmp[1] = (byte)(x >> 56); + tmp[2] = (byte)(x >> 48); + tmp[3] = (byte)(x >> 40); + tmp[4] = (byte)(x >> 32); + tmp[5] = (byte)(x >> 24); + tmp[6] = (byte)(x >> 16); + tmp[7] = (byte)(x >> 8); + tmp[8] = (byte)x; + _strm.Write (tmp, 0, 9); + } + } + + public void WriteNil () + { + _strm.WriteByte (0xc0); + } + + public void Write (bool x) + { + _strm.WriteByte ((byte)(x ? 0xc3 : 0xc2)); + } + + public void Write (float x) + { + byte[] raw = BitConverter.GetBytes (x); // unsafeコードを使う? + byte[] tmp = _tmp; + + tmp[0] = 0xca; + if (BitConverter.IsLittleEndian) { + tmp[1] = raw[3]; + tmp[2] = raw[2]; + tmp[3] = raw[1]; + tmp[4] = raw[0]; + } else { + tmp[1] = raw[0]; + tmp[2] = raw[1]; + tmp[3] = raw[2]; + tmp[4] = raw[3]; + } + _strm.Write (tmp, 0, 5); + } + + public void Write (double x) + { + byte[] raw = BitConverter.GetBytes (x); // unsafeコードを使う? + byte[] tmp = _tmp; + + tmp[0] = 0xcb; + if (BitConverter.IsLittleEndian) { + tmp[1] = raw[7]; + tmp[2] = raw[6]; + tmp[3] = raw[5]; + tmp[4] = raw[4]; + tmp[5] = raw[3]; + tmp[6] = raw[2]; + tmp[7] = raw[1]; + tmp[8] = raw[0]; + } else { + tmp[1] = raw[0]; + tmp[2] = raw[1]; + tmp[3] = raw[2]; + tmp[4] = raw[3]; + tmp[5] = raw[4]; + tmp[6] = raw[5]; + tmp[7] = raw[6]; + tmp[8] = raw[7]; + } + _strm.Write (tmp, 0, 9); + } + + public void Write (byte[] bytes) + { + WriteRawHeader (bytes.Length); + _strm.Write (bytes, 0, bytes.Length); + } + + public void WriteRawHeader (int N) + { + WriteLengthHeader (N, 32, 0xa0, 0xda, 0xdb); + } + + public void WriteArrayHeader (int N) + { + WriteLengthHeader (N, 16, 0x90, 0xdc, 0xdd); + } + + public void WriteMapHeader (int N) + { + WriteLengthHeader (N, 16, 0x80, 0xde, 0xdf); + } + + void WriteLengthHeader (int N, int fix_length, byte fix_prefix, byte len16bit_prefix, byte len32bit_prefix) + { + if (N < fix_length) { + _strm.WriteByte ((byte)(fix_prefix | N)); + } else { + byte[] tmp = _tmp; + int header_len; + if (N < 0x10000) { + tmp[0] = len16bit_prefix; + tmp[1] = (byte)(N >> 8); + tmp[2] = (byte)N; + header_len = 3; + } else { + tmp[0] = len32bit_prefix; + tmp[1] = (byte)(N >> 24); + tmp[2] = (byte)(N >> 16); + tmp[3] = (byte)(N >> 8); + tmp[4] = (byte)N; + header_len = 5; + } + _strm.Write (tmp, 0, header_len); + } + } + + public void Write (string x) + { + Write (x, false); + } + + public void Write (string x, bool highProbAscii) + { + Write (x, _buf, highProbAscii); + } + + public void Write (string x, byte[] buf) + { + Write (x, buf, false); + } + + public unsafe void Write (string x, byte[] buf, bool highProbAscii) + { + Encoder encoder = _encoder; + fixed (char *pstr = x) + fixed (byte *pbuf = buf) { + if (highProbAscii && x.Length <= buf.Length) { + bool isAsciiFullCompatible = true; + for (int i = 0; i < x.Length; i ++) { + int v = (int)pstr[i]; + if (v > 0x7f) { + isAsciiFullCompatible = false; + break; + } + buf[i] = (byte)v; + } + if (isAsciiFullCompatible) { + WriteRawHeader (x.Length); + _strm.Write (buf, 0, x.Length); + return; + } + } + + WriteRawHeader (encoder.GetByteCount (pstr, x.Length, true)); + int str_len = x.Length; + char *p = pstr; + int convertedChars, bytesUsed; + bool completed = true; + while (str_len > 0 || !completed) { + encoder.Convert (p, str_len, pbuf, buf.Length, false, out convertedChars, out bytesUsed, out completed); + _strm.Write (buf, 0, bytesUsed); + str_len -= convertedChars; + p += convertedChars; + } + } + } + } +} diff --git a/csharp/MsgPack/ObjectPacker.cs b/csharp/MsgPack/ObjectPacker.cs new file mode 100644 index 00000000..08f47966 --- /dev/null +++ b/csharp/MsgPack/ObjectPacker.cs @@ -0,0 +1,259 @@ +// +// Copyright 2011 Kazuki Oikawa +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Runtime.Serialization; +using System.Text; + +namespace MsgPack +{ + public class ObjectPacker + { + byte[] _buf = new byte[64]; + Encoding _encoding = Encoding.UTF8; + static Dictionary PackerMapping; + static Dictionary UnpackerMapping; + + delegate void PackDelegate (ObjectPacker packer, MsgPackWriter writer, object o); + delegate object UnpackDelegate (ObjectPacker packer, MsgPackReader reader); + + static ObjectPacker () + { + PackerMapping = new Dictionary (); + UnpackerMapping = new Dictionary (); + + PackerMapping.Add (typeof (string), StringPacker); + UnpackerMapping.Add (typeof (string), StringUnpacker); + } + + public byte[] Pack (object o) + { + using (MemoryStream ms = new MemoryStream ()) { + Pack (ms, o); + return ms.ToArray (); + } + } + + public void Pack (Stream strm, object o) + { + if (o != null && o.GetType ().IsPrimitive) + throw new NotSupportedException (); + MsgPackWriter writer = new MsgPackWriter (strm); + Pack (writer, o); + } + + void Pack (MsgPackWriter writer, object o) + { + if (o == null) { + writer.WriteNil (); + return; + } + + Type t = o.GetType (); + if (t.IsPrimitive) { + if (t.Equals (typeof (int))) writer.Write ((int)o); + else if (t.Equals (typeof (uint))) writer.Write ((uint)o); + else if (t.Equals (typeof (float))) writer.Write ((float)o); + else if (t.Equals (typeof (double))) writer.Write ((double)o); + else if (t.Equals (typeof (long))) writer.Write ((long)o); + else if (t.Equals (typeof (ulong))) writer.Write ((ulong)o); + else if (t.Equals (typeof (bool))) writer.Write ((bool)o); + else if (t.Equals (typeof (byte))) writer.Write ((byte)o); + else if (t.Equals (typeof (sbyte))) writer.Write ((sbyte)o); + else if (t.Equals (typeof (short))) writer.Write ((short)o); + else if (t.Equals (typeof (ushort))) writer.Write ((ushort)o); + else if (t.Equals (typeof (char))) writer.Write ((ushort)(char)o); + else throw new NotSupportedException (); + return; + } + + PackDelegate packer; + if (PackerMapping.TryGetValue (t, out packer)) { + packer (this, writer, o); + return; + } + + if (t.IsArray) { + Array ary = (Array)o; + writer.WriteArrayHeader (ary.Length); + for (int i = 0; i < ary.Length; i ++) + Pack (writer, ary.GetValue (i)); + return; + } + + ReflectionCacheEntry entry = ReflectionCache.Lookup (t); + writer.WriteMapHeader (entry.FieldMap.Count); + foreach (KeyValuePair pair in entry.FieldMap) { + writer.Write (pair.Key, _buf); + object v = pair.Value.GetValue (o); + if (pair.Value.FieldType.IsInterface && v != null) { + writer.WriteArrayHeader (2); + writer.Write (v.GetType().FullName); + } + Pack (writer, v); + } + } + + public T Unpack (byte[] buf) + { + return Unpack (buf, 0, buf.Length); + } + + public T Unpack (byte[] buf, int offset, int size) + { + using (MemoryStream ms = new MemoryStream (buf, offset, size)) { + return Unpack (ms); + } + } + + public T Unpack (Stream strm) + { + if (typeof (T).IsPrimitive) + throw new NotSupportedException (); + MsgPackReader reader = new MsgPackReader (strm); + return (T)Unpack (reader, typeof (T)); + } + + public object Unpack (Type type, byte[] buf) + { + return Unpack (type, buf, 0, buf.Length); + } + + public object Unpack (Type type, byte[] buf, int offset, int size) + { + using (MemoryStream ms = new MemoryStream (buf, offset, size)) { + return Unpack (type, ms); + } + } + + public object Unpack (Type type, Stream strm) + { + if (type.IsPrimitive) + throw new NotSupportedException (); + MsgPackReader reader = new MsgPackReader (strm); + return Unpack (reader, type); + } + + object Unpack (MsgPackReader reader, Type t) + { + if (t.IsPrimitive) { + if (!reader.Read ()) throw new FormatException (); + if (t.Equals (typeof (int)) && reader.IsSigned ()) return reader.ValueSigned; + else if (t.Equals (typeof (uint)) && reader.IsUnsigned ()) return reader.ValueUnsigned; + else if (t.Equals (typeof (float)) && reader.Type == TypePrefixes.Float) return reader.ValueFloat; + else if (t.Equals (typeof (double)) && reader.Type == TypePrefixes.Double) return reader.ValueDouble; + else if (t.Equals (typeof (long))) { + if (reader.IsSigned64 ()) + return reader.ValueSigned64; + if (reader.IsSigned ()) + return (long)reader.ValueSigned; + } else if (t.Equals (typeof (ulong))) { + if (reader.IsUnsigned64 ()) + return reader.ValueUnsigned64; + if (reader.IsUnsigned ()) + return (ulong)reader.ValueUnsigned; + } else if (t.Equals (typeof (bool)) && reader.IsBoolean ()) return (reader.Type == TypePrefixes.True); + else if (t.Equals (typeof (byte)) && reader.IsUnsigned ()) return (byte)reader.ValueUnsigned; + else if (t.Equals (typeof (sbyte)) && reader.IsSigned ()) return (sbyte)reader.ValueSigned; + else if (t.Equals (typeof (short)) && reader.IsSigned ()) return (short)reader.ValueSigned; + else if (t.Equals (typeof (ushort)) && reader.IsUnsigned ()) return (ushort)reader.ValueUnsigned; + else if (t.Equals (typeof (char)) && reader.IsUnsigned ()) return (char)reader.ValueUnsigned; + else throw new NotSupportedException (); + } + + UnpackDelegate unpacker; + if (UnpackerMapping.TryGetValue (t, out unpacker)) + return unpacker (this, reader); + + if (t.IsArray) { + if (!reader.Read () || (!reader.IsArray () && reader.Type != TypePrefixes.Nil)) + throw new FormatException (); + if (reader.Type == TypePrefixes.Nil) + return null; + Type et = t.GetElementType (); + Array ary = Array.CreateInstance (et, (int)reader.Length); + for (int i = 0; i < ary.Length; i ++) + ary.SetValue (Unpack (reader, et), i); + return ary; + } + + if (!reader.Read ()) + throw new FormatException (); + if (reader.Type == TypePrefixes.Nil) + return null; + if (t.IsInterface) { + if (reader.Type != TypePrefixes.FixArray && reader.Length != 2) + throw new FormatException (); + if (!reader.Read () || !reader.IsRaw ()) + throw new FormatException (); + CheckBufferSize ((int)reader.Length); + reader.ReadValueRaw (_buf, 0, (int)reader.Length); + t = Type.GetType (Encoding.UTF8.GetString (_buf, 0, (int)reader.Length)); + if (!reader.Read () || reader.Type == TypePrefixes.Nil) + throw new FormatException (); + } + if (!reader.IsMap ()) + throw new FormatException (); + + object o = FormatterServices.GetUninitializedObject (t); + ReflectionCacheEntry entry = ReflectionCache.Lookup (t); + int members = (int)reader.Length; + for (int i = 0; i < members; i ++) { + if (!reader.Read () || !reader.IsRaw ()) + throw new FormatException (); + CheckBufferSize ((int)reader.Length); + reader.ReadValueRaw (_buf, 0, (int)reader.Length); + string name = Encoding.UTF8.GetString (_buf, 0, (int)reader.Length); + FieldInfo f; + if (!entry.FieldMap.TryGetValue (name, out f)) + throw new FormatException (); + f.SetValue (o, Unpack (reader, f.FieldType)); + } + + IDeserializationCallback callback = o as IDeserializationCallback; + if (callback != null) + callback.OnDeserialization (this); + return o; + } + + void CheckBufferSize (int size) + { + if (_buf.Length < size) + Array.Resize (ref _buf, size); + } + + static void StringPacker (ObjectPacker packer, MsgPackWriter writer, object o) + { + writer.Write (Encoding.UTF8.GetBytes ((string)o)); + } + + static object StringUnpacker (ObjectPacker packer, MsgPackReader reader) + { + if (!reader.Read ()) + throw new FormatException (); + if (reader.Type == TypePrefixes.Nil) + return null; + if (!reader.IsRaw ()) + throw new FormatException (); + packer.CheckBufferSize ((int)reader.Length); + reader.ReadValueRaw (packer._buf, 0, (int)reader.Length); + return Encoding.UTF8.GetString (packer._buf, 0, (int)reader.Length); + } + } +} diff --git a/csharp/MsgPack/ReflectionCache.cs b/csharp/MsgPack/ReflectionCache.cs new file mode 100644 index 00000000..34d46e7b --- /dev/null +++ b/csharp/MsgPack/ReflectionCache.cs @@ -0,0 +1,60 @@ +// +// Copyright 2011 Kazuki Oikawa +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; + +namespace MsgPack +{ + public static class ReflectionCache + { + static Dictionary _cache; + + static ReflectionCache () + { + _cache = new Dictionary (); + } + + public static ReflectionCacheEntry Lookup (Type type) + { + ReflectionCacheEntry entry; + lock (_cache) { + if (_cache.TryGetValue (type, out entry)) + return entry; + } + + entry = new ReflectionCacheEntry (type); + lock (_cache) { + _cache[type] = entry; + } + return entry; + } + + public static void RemoveCache (Type type) + { + lock (_cache) { + _cache.Remove (type); + } + } + + public static void Clear () + { + lock (_cache) { + _cache.Clear (); + } + } + } +} diff --git a/csharp/MsgPack/ReflectionCacheEntry.cs b/csharp/MsgPack/ReflectionCacheEntry.cs new file mode 100644 index 00000000..bec4d4c4 --- /dev/null +++ b/csharp/MsgPack/ReflectionCacheEntry.cs @@ -0,0 +1,44 @@ +// +// Copyright 2011 Kazuki Oikawa +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace MsgPack +{ + public class ReflectionCacheEntry + { + const BindingFlags FieldBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.SetField; + + public ReflectionCacheEntry (Type t) + { + FieldInfo[] fields = t.GetFields (FieldBindingFlags); + IDictionary map = new Dictionary (fields.Length); + for (int i = 0; i < fields.Length; i ++) { + FieldInfo f = fields[i]; + string name = f.Name; + int pos; + if (name[0] == '<' && (pos = name.IndexOf ('>')) > 1) + name = name.Substring (1, pos - 1); // Auto-Property (\<.+\>) + map[name] = f; + } + FieldMap = map; + } + + public IDictionary FieldMap { get; private set; } + } +} diff --git a/csharp/MsgPack/TypePrefixes.cs b/csharp/MsgPack/TypePrefixes.cs new file mode 100644 index 00000000..a7c97a61 --- /dev/null +++ b/csharp/MsgPack/TypePrefixes.cs @@ -0,0 +1,48 @@ +// +// Copyright 2011 Kazuki Oikawa +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace MsgPack +{ + public enum TypePrefixes : byte + { + PositiveFixNum = 0x00, // 0x00 - 0x7f + NegativeFixNum = 0xe0, // 0xe0 - 0xff + + Nil = 0xc0, + False = 0xc2, + True = 0xc3, + Float = 0xca, + Double = 0xcb, + UInt8 = 0xcc, + UInt16 = 0xcd, + UInt32 = 0xce, + UInt64 = 0xcf, + Int8 = 0xd0, + Int16 = 0xd1, + Int32 = 0xd2, + Int64 = 0xd3, + Raw16 = 0xda, + Raw32 = 0xdb, + Array16 = 0xdc, + Array32 = 0xdd, + Map16 = 0xde, + Map32 = 0xdf, + + FixRaw = 0xa0, // 0xa0 - 0xbf + FixArray = 0x90, // 0x90 - 0x9f + FixMap = 0x80, // 0x80 - 0x8f + } +} diff --git a/java/.settings/org.eclipse.jdt.core.prefs b/java/.settings/org.eclipse.jdt.core.prefs index c2f9169f..e36c739a 100755 --- a/java/.settings/org.eclipse.jdt.core.prefs +++ b/java/.settings/org.eclipse.jdt.core.prefs @@ -1,6 +1,13 @@ -#Mon Sep 27 07:43:48 JST 2010 +#Tue Apr 12 19:14:17 JST 2011 eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning org.eclipse.jdt.core.compiler.source=1.6 diff --git a/java/CHANGES.txt b/java/CHANGES.txt index a985ebd4..e7cbcfd6 100644 --- a/java/CHANGES.txt +++ b/java/CHANGES.txt @@ -1,4 +1,23 @@ +Release 0.5.2 - 2011/04/23 + NEW FEATURES + MSGPACK-6 Added TemplatePrecompiler program + + Added built-in templates of BigDecimal and Date classes. + + Added @MessagePackBeans annotation that enables you to serialize/deserialize + JavaBeans. + + BUG FIXES + MSGPACK-4 Fixes the deserialization routine of Long value + + IMPROVEMENTS + #35 Improves handling of ClassLoader on Javassist template builder. + + MSGPACK-7 Improves compatibility with Java 1.5. Now it runs on JRE 5. + It is tested on Jenkins CI: http://ci.msgpack.org/job/java-jre5/ + + Release 0.5.1 - 2010/12/14 BUG FIXES Fixes cast error on GenericArrayType diff --git a/java/pom.xml b/java/pom.xml index 5d241150..c4e9824b 100755 --- a/java/pom.xml +++ b/java/pom.xml @@ -2,8 +2,8 @@ 4.0.0 org.msgpack - msgpack - 0.5.2-SNAPSHOT + msgpack + 0.5.2-SNAPSHOT MessagePack for Java MessagePack for Java diff --git a/java/src/main/java/org/msgpack/template/builder/BeansBuildContext.java b/java/src/main/java/org/msgpack/template/builder/BeansBuildContext.java index af88d3ff..652a34f0 100644 --- a/java/src/main/java/org/msgpack/template/builder/BeansBuildContext.java +++ b/java/src/main/java/org/msgpack/template/builder/BeansBuildContext.java @@ -280,6 +280,6 @@ public class BeansBuildContext extends BuildContextBase { @Override public Template loadTemplate(Class targetClass, BeansFieldEntry[] entries, Template[] templates) { - throw new UnsupportedOperationException(targetClass.getName()); + return null; } } \ No newline at end of file diff --git a/java/src/main/java/org/msgpack/template/builder/BuilderSelectorRegistry.java b/java/src/main/java/org/msgpack/template/builder/BuilderSelectorRegistry.java index f5d5a5be..5ec0552e 100644 --- a/java/src/main/java/org/msgpack/template/builder/BuilderSelectorRegistry.java +++ b/java/src/main/java/org/msgpack/template/builder/BuilderSelectorRegistry.java @@ -54,14 +54,9 @@ public class BuilderSelectorRegistry { */ private static void initForJava(){ instance.append(new ArrayTemplateBuilderSelector()); - if(isSupportJavassist()){ - instance.append( - new AnnotationTemplateBuilderSelector( - new JavassistTemplateBuilder())); + instance.append(new AnnotationTemplateBuilderSelector(new JavassistTemplateBuilder())); instance.forceBuilder = new JavassistTemplateBuilder(); - - //Java beans instance.append(new BeansTemplateBuilderSelector( new JavassistTemplateBuilder( new BeansFieldEntryReader(), @@ -73,22 +68,17 @@ public class BuilderSelectorRegistry { } ))); }else{ - instance.append( - new AnnotationTemplateBuilderSelector( - new ReflectionTemplateBuilder())); + instance.append(new AnnotationTemplateBuilderSelector(new ReflectionTemplateBuilder())); instance.forceBuilder = new ReflectionTemplateBuilder(); - - //Java beans - instance.append(new BeansTemplateBuilderSelector( - new BeansTemplateBuilder())); + instance.append(new BeansTemplateBuilderSelector(new BeansTemplateBuilder())); } - instance.append(new OrdinalEnumTemplateBuilderSelector()); instance.append(new EnumTemplateBuilderSelector()); } + public static boolean isSupportJavassist(){ try { - return System.getProperty("java.vm.name").equals("Dalvik"); + return !System.getProperty("java.vm.name").equals("Dalvik"); } catch (Exception e) { return true; } @@ -112,7 +102,6 @@ public class BuilderSelectorRegistry { * @param builderSelector */ public void append(BuilderSelector builderSelector){ - if(contains(builderSelector.getName())){ throw new RuntimeException("Duplicate BuilderSelector name:" + builderSelector.getName()); } diff --git a/java/src/main/java/org/msgpack/template/builder/JavassistTemplateBuilder.java b/java/src/main/java/org/msgpack/template/builder/JavassistTemplateBuilder.java index f174f03d..ae50f257 100644 --- a/java/src/main/java/org/msgpack/template/builder/JavassistTemplateBuilder.java +++ b/java/src/main/java/org/msgpack/template/builder/JavassistTemplateBuilder.java @@ -112,7 +112,7 @@ public class JavassistTemplateBuilder extends CustomTemplateBuilder { * @param reader * @param buildContextFactory */ - public JavassistTemplateBuilder(IFieldEntryReader reader,BuildContextFactory buildContextFactory ){ + public JavassistTemplateBuilder(IFieldEntryReader reader, BuildContextFactory buildContextFactory ){ this(); this.reader = reader; this.buildContextFactory = buildContextFactory; diff --git a/java/src/main/java/org/msgpack/util/TemplatePrecompiler.java b/java/src/main/java/org/msgpack/util/TemplatePrecompiler.java index d1d23f6c..36414f5c 100644 --- a/java/src/main/java/org/msgpack/util/TemplatePrecompiler.java +++ b/java/src/main/java/org/msgpack/util/TemplatePrecompiler.java @@ -19,43 +19,98 @@ package org.msgpack.util; import java.io.File; import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.tools.DiagnosticCollector; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; -import org.msgpack.template.builder.BuilderSelectorRegistry; import org.msgpack.template.builder.JavassistTemplateBuilder; -import org.msgpack.template.builder.TemplateBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * This class is a template precompiler, which is used for saving templates + * that TemplateBuilder generated. It saves templates as .class files. + * Application enables to load the .class files and use templates. + * + */ public class TemplatePrecompiler { + private static final Logger LOG = LoggerFactory.getLogger(TemplatePrecompiler.class); - //public static final String SRC = "msgpack.template.srcdir"; + public static final String DEST = "msgpack.template.destdir"; - public static final String DIST = "msgpack.template.distdir"; + public static final String DEFAULT_DEST = "."; - //public static final String DEFAULT_SRC = "."; - - public static final String DEFAULT_DIST = "."; - - private static TemplatePrecompiler INSTANCE = null; - - private TemplatePrecompiler() { + public static void saveTemplates(final String[] classNames) throws IOException, ClassNotFoundException { + List ret = new ArrayList(); + for (String className : classNames) { + matchClassNames(ret, className); + } + List> ret0 = toClass(ret); + for (Class c : ret0) { + saveTemplateClass(c); + } } - public static void saveTemplates(final String[] classFileNames) throws IOException { - throw new UnsupportedOperationException("Not supported yet.");// TODO + @SuppressWarnings("serial") + private static void matchClassNames(List ret, final String className) throws IOException { + String packageName = className.substring(0, className.lastIndexOf('.')); + String relativedName = className.substring(className.lastIndexOf('.') + 1, className.length()); + String patName = relativedName.replace("*", "(\\w+)"); + Pattern pat = Pattern.compile(patName); + + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + JavaFileManager fm = compiler.getStandardFileManager( + new DiagnosticCollector(), null, null); + HashSet kind = new HashSet(){{ + add(JavaFileObject.Kind.CLASS); + }}; + + for (JavaFileObject f : fm.list(StandardLocation.PLATFORM_CLASS_PATH, packageName, kind, false)) { + String relatived0 = f.getName(); + String name0 = relatived0.substring(0, relatived0.length() - ".class".length()); + Matcher m = pat.matcher(name0); + if (m.matches()) { + String name = packageName + '.' + name0; + if (!ret.contains(name)) { + ret.add(name); + } + } + } + } + + private static List> toClass(List classNames) throws ClassNotFoundException { + List> ret = new ArrayList>(classNames.size()); + ClassLoader cl = TemplatePrecompiler.class.getClassLoader(); + for (String className : classNames) { + Class c = cl.loadClass(className); + ret.add(c); + } + return ret; + } + + public static void saveTemplateClasses(Class[] targetClasses) throws IOException { + for (Class c : targetClasses) { + saveTemplateClass(c); + } } public static void saveTemplateClass(Class targetClass) throws IOException { - if (INSTANCE != null) { - INSTANCE = new TemplatePrecompiler(); - } LOG.info("Saving template of " + targetClass.getName() + "..."); Properties props = System.getProperties(); - String distDirName = getDirName(props, DIST, DEFAULT_DIST); + String distDirName = getDirName(props, DEST, DEFAULT_DEST); if (targetClass.isEnum()) { - throw new UnsupportedOperationException("Enum not supported yet: " + targetClass.getName()); + throw new UnsupportedOperationException("Not supported enum type yet: " + targetClass.getName()); } else { new JavassistTemplateBuilder().writeTemplate(targetClass, distDirName); } diff --git a/java/src/test/java/org/msgpack/util/TestTemplatePrecompiler.java b/java/src/test/java/org/msgpack/util/TestTemplatePrecompiler.java deleted file mode 100644 index e99c5da1..00000000 --- a/java/src/test/java/org/msgpack/util/TestTemplatePrecompiler.java +++ /dev/null @@ -1,110 +0,0 @@ -package org.msgpack.util; - -import org.junit.Test; -import static org.junit.Assert.*; -import org.msgpack.MessagePack; -import org.msgpack.MessageTypeException; -import org.msgpack.template.TemplateRegistry; - -public class TestTemplatePrecompiler { - - @Test - public void testPrimitiveTypeFields00() throws Exception { - System.getProperties().setProperty(TemplatePrecompiler.DIST, "./target/test-classes"); - Class c = PrimitiveTypeFieldsClass.class; - TemplatePrecompiler.saveTemplateClass(PrimitiveTypeFieldsClass.class); - - PrimitiveTypeFieldsClass src = new PrimitiveTypeFieldsClass(); - src.f0 = (byte) 0; - src.f1 = 1; - src.f2 = 2; - src.f3 = 3; - src.f4 = 4; - src.f5 = 5; - src.f6 = false; - - try { - MessagePack.pack(src); - fail(); - } catch (Exception e) { - assertTrue(e instanceof MessageTypeException); - assertTrue(TemplateRegistry.unregister(c)); - } - try { - TemplateRegistry.lookup(c, true, true); - byte[] raw = MessagePack.pack(src); - PrimitiveTypeFieldsClass dst = MessagePack.unpack(raw, PrimitiveTypeFieldsClass.class); - assertEquals(src.f0, dst.f0); - assertEquals(src.f1, dst.f1); - assertEquals(src.f2, dst.f2); - assertEquals(src.f3, dst.f3); - //assertEquals(src.f4, dst.f4); - //assertEquals(src.f5, dst.f5); - assertEquals(src.f6, dst.f6); - } finally { - TemplateRegistry.unregister(c); - } - } - - @Test - public void testPrimitiveTypeFields01() throws Exception { - System.getProperties().setProperty(TemplatePrecompiler.DIST, "./target/test-classes"); - Class c = PrimitiveTypeFieldsClass.class; - TemplatePrecompiler.saveTemplateClass(PrimitiveTypeFieldsClass.class); - - PrimitiveTypeFieldsClass src = new PrimitiveTypeFieldsClass(); - - try { - MessagePack.pack(src); - fail(); - } catch (Exception e) { - assertTrue(e instanceof MessageTypeException); - assertTrue(TemplateRegistry.unregister(c)); - } - try { - TemplateRegistry.lookup(c, true, true); - byte[] raw = MessagePack.pack(src); - PrimitiveTypeFieldsClass dst = MessagePack.unpack(raw, PrimitiveTypeFieldsClass.class); - assertEquals(src.f0, dst.f0); - assertEquals(src.f1, dst.f1); - assertEquals(src.f2, dst.f2); - assertEquals(src.f3, dst.f3); - //assertEquals(src.f4, dst.f4); - //assertEquals(src.f5, dst.f5); - assertEquals(src.f6, dst.f6); - } finally { - TemplateRegistry.unregister(c); - } - } - - @Test - public void testPrimitiveTypeFields02() throws Exception { - System.getProperties().setProperty(TemplatePrecompiler.DIST, "./target/test-classes"); - Class c = PrimitiveTypeFieldsClass.class; - TemplatePrecompiler.saveTemplateClass(PrimitiveTypeFieldsClass.class); - - PrimitiveTypeFieldsClass src = null; - MessagePack.pack(src); - try { - TemplateRegistry.lookup(c, true, true); - byte[] raw = MessagePack.pack(src); - PrimitiveTypeFieldsClass dst = MessagePack.unpack(raw, PrimitiveTypeFieldsClass.class); - assertEquals(src, dst); - } finally { - TemplateRegistry.unregister(c); - } - } - - public static class PrimitiveTypeFieldsClass { - public byte f0; - public short f1; - public int f2; - public long f3; - public float f4; - public double f5; - public boolean f6; - - public PrimitiveTypeFieldsClass() { - } - } -} diff --git a/java/src/test/java/org/msgpack/util/TestTemplatePrecompilerPackConvert.java b/java/src/test/java/org/msgpack/util/TestTemplatePrecompilerPackConvert.java new file mode 100644 index 00000000..455f0f3c --- /dev/null +++ b/java/src/test/java/org/msgpack/util/TestTemplatePrecompilerPackConvert.java @@ -0,0 +1,1360 @@ +package org.msgpack.util; + +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.junit.Test; +import org.msgpack.MessagePack; +import org.msgpack.annotation.MessagePackMessage; +import org.msgpack.annotation.Optional; +import org.msgpack.template.TemplateBuildException; +import org.msgpack.template.TemplateRegistry; + +import junit.framework.TestCase; + +public class TestTemplatePrecompilerPackConvert extends TestCase { + + @Test + public void testPrimitiveTypeFields00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(PrimitiveTypeFieldsClass.class); + + PrimitiveTypeFieldsClass src = new PrimitiveTypeFieldsClass(); + src.f0 = (byte) 0; + src.f1 = 1; + src.f2 = 2; + src.f3 = 3; + src.f4 = 4; + src.f5 = 5; + src.f6 = false; + + try { + byte[] raw = MessagePack.pack(src); + PrimitiveTypeFieldsClass dst = MessagePack.unpack(raw).convert( + PrimitiveTypeFieldsClass.class); + assertEquals(src.f0, dst.f0); + assertEquals(src.f1, dst.f1); + assertEquals(src.f2, dst.f2); + assertEquals(src.f3, dst.f3); + assertEquals(src.f4, dst.f4); + assertEquals(src.f5, dst.f5); + assertEquals(src.f6, dst.f6); + } finally { + TemplateRegistry.unregister(PrimitiveTypeFieldsClass.class); + } + } + + @Test + public void testPrimitiveTypeFields01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(PrimitiveTypeFieldsClass.class); + + PrimitiveTypeFieldsClass src = new PrimitiveTypeFieldsClass(); + + try { + byte[] raw = MessagePack.pack(src); + PrimitiveTypeFieldsClass dst = MessagePack.unpack(raw).convert( + PrimitiveTypeFieldsClass.class); + assertEquals(src.f0, dst.f0); + assertEquals(src.f1, dst.f1); + assertEquals(src.f2, dst.f2); + assertEquals(src.f3, dst.f3); + assertEquals(src.f4, dst.f4); + assertEquals(src.f5, dst.f5); + assertEquals(src.f6, dst.f6); + } finally { + TemplateRegistry.unregister(PrimitiveTypeFieldsClass.class); + } + } + + @Test + public void testPrimitiveTypeFields02() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(PrimitiveTypeFieldsClass.class); + + PrimitiveTypeFieldsClass src = null; + + try { + byte[] raw = MessagePack.pack(src); + PrimitiveTypeFieldsClass dst = MessagePack.unpack(raw).convert( + PrimitiveTypeFieldsClass.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(PrimitiveTypeFieldsClass.class); + } + } + + @MessagePackMessage + public static class PrimitiveTypeFieldsClass { + public byte f0; + public short f1; + public int f2; + public long f3; + public float f4; + public double f5; + public boolean f6; + + public PrimitiveTypeFieldsClass() { + } + } + + @Test + public void testOptionalPrimitiveTypeFields00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(OptionalPrimitiveTypeFieldsClass.class); + + OptionalPrimitiveTypeFieldsClass src = new OptionalPrimitiveTypeFieldsClass(); + src.f0 = (byte) 0; + src.f1 = 1; + src.f2 = 2; + src.f3 = 3; + src.f4 = 4; + src.f5 = 5; + src.f6 = false; + + try { + byte[] raw = MessagePack.pack(src); + PrimitiveTypeFieldsClass dst = MessagePack.unpack(raw).convert( + PrimitiveTypeFieldsClass.class); + assertEquals(src.f0, dst.f0); + assertEquals(src.f1, dst.f1); + assertEquals(src.f2, dst.f2); + assertEquals(src.f3, dst.f3); + assertEquals(src.f4, dst.f4); + assertEquals(src.f5, dst.f5); + assertEquals(src.f6, dst.f6); + } finally { + TemplateRegistry.unregister(OptionalPrimitiveTypeFieldsClass.class); + } + } + + @Test + public void testOptionalPrimitiveTypeFields01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(OptionalPrimitiveTypeFieldsClass.class); + + OptionalPrimitiveTypeFieldsClass src = new OptionalPrimitiveTypeFieldsClass(); + + try { + byte[] raw = MessagePack.pack(src); + OptionalPrimitiveTypeFieldsClass dst = MessagePack.unpack(raw) + .convert(OptionalPrimitiveTypeFieldsClass.class); + assertEquals(src.f0, dst.f0); + assertEquals(src.f1, dst.f1); + assertEquals(src.f2, dst.f2); + assertEquals(src.f3, dst.f3); + assertEquals(src.f4, dst.f4); + assertEquals(src.f5, dst.f5); + assertEquals(src.f6, dst.f6); + } finally { + TemplateRegistry.unregister(OptionalPrimitiveTypeFieldsClass.class); + } + } + + @Test + public void testOptionalPrimitiveTypeFields02() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(OptionalPrimitiveTypeFieldsClass.class); + + OptionalPrimitiveTypeFieldsClass src = null; + + try { + byte[] raw = MessagePack.pack(src); + OptionalPrimitiveTypeFieldsClass dst = MessagePack.unpack(raw) + .convert(OptionalPrimitiveTypeFieldsClass.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(OptionalPrimitiveTypeFieldsClass.class); + } + } + + @MessagePackMessage + public static class OptionalPrimitiveTypeFieldsClass { + @Optional + public byte f0; + @Optional + public short f1; + @Optional + public int f2; + @Optional + public long f3; + @Optional + public float f4; + @Optional + public double f5; + @Optional + public boolean f6; + + public OptionalPrimitiveTypeFieldsClass() { + } + } + + @Test + public void testGeneralReferenceTypeFieldsClass00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(GeneralReferenceTypeFieldsClass.class); + + GeneralReferenceTypeFieldsClass src = new GeneralReferenceTypeFieldsClass(); + src.f0 = 0; + src.f1 = 1; + src.f2 = 2; + src.f3 = (long) 3; + src.f4 = (float) 4; + src.f5 = (double) 5; + src.f6 = false; + src.f7 = new BigInteger("7"); + src.f8 = "8"; + src.f9 = new byte[] { 0x01, 0x02 }; + src.f10 = ByteBuffer.wrap("muga".getBytes()); + + try { + byte[] raw = MessagePack.pack(src); + GeneralReferenceTypeFieldsClass dst = MessagePack.unpack(raw) + .convert(GeneralReferenceTypeFieldsClass.class); + assertEquals(src.f0, dst.f0); + assertEquals(src.f1, dst.f1); + assertEquals(src.f2, dst.f2); + assertEquals(src.f3, dst.f3); + assertEquals(src.f4, dst.f4); + assertEquals(src.f5, dst.f5); + assertEquals(src.f6, dst.f6); + assertEquals(src.f7, dst.f7); + assertEquals(src.f8, dst.f8); + assertEquals(src.f9[0], dst.f9[0]); + assertEquals(src.f9[1], dst.f9[1]); + assertEquals(src.f10, dst.f10); + } finally { + TemplateRegistry.unregister(GeneralReferenceTypeFieldsClass.class); + } + } + + @Test + public void testGeneralReferenceTypeFieldsClass01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(GeneralReferenceTypeFieldsClass.class); + + GeneralReferenceTypeFieldsClass src = null; + + try { + byte[] raw = MessagePack.pack(src); + GeneralReferenceTypeFieldsClass dst = MessagePack.unpack(raw) + .convert(GeneralReferenceTypeFieldsClass.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(GeneralReferenceTypeFieldsClass.class); + } + } + + @MessagePackMessage + public static class GeneralReferenceTypeFieldsClass { + public Byte f0; + public Short f1; + public Integer f2; + public Long f3; + public Float f4; + public Double f5; + public Boolean f6; + public BigInteger f7; + public String f8; + public byte[] f9; + public ByteBuffer f10; + + public GeneralReferenceTypeFieldsClass() { + } + } + + @Test + public void testGeneralOptionalReferenceTypeFieldsClass00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(GeneralOptionalReferenceTypeFieldsClass.class); + + GeneralOptionalReferenceTypeFieldsClass src = new GeneralOptionalReferenceTypeFieldsClass(); + src.f0 = 0; + src.f1 = 1; + src.f2 = 2; + src.f3 = (long) 3; + src.f4 = (float) 4; + src.f5 = (double) 5; + src.f6 = false; + src.f7 = new BigInteger("7"); + src.f8 = "8"; + src.f9 = new byte[] { 0x01, 0x02 }; + src.f10 = ByteBuffer.wrap("muga".getBytes()); + + try { + byte[] raw = MessagePack.pack(src); + GeneralOptionalReferenceTypeFieldsClass dst = MessagePack.unpack( + raw).convert(GeneralOptionalReferenceTypeFieldsClass.class); + assertEquals(src.f0, dst.f0); + assertEquals(src.f1, dst.f1); + assertEquals(src.f2, dst.f2); + assertEquals(src.f3, dst.f3); + assertEquals(src.f4, dst.f4); + assertEquals(src.f5, dst.f5); + assertEquals(src.f6, dst.f6); + assertEquals(src.f7, dst.f7); + assertEquals(src.f8, dst.f8); + assertEquals(src.f9[0], dst.f9[0]); + assertEquals(src.f9[1], dst.f9[1]); + assertEquals(src.f10, dst.f10); + } finally { + TemplateRegistry.unregister(GeneralOptionalReferenceTypeFieldsClass.class); + } + } + + @Test + public void testGeneralOptionalReferenceTypeFieldsClass01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(GeneralOptionalReferenceTypeFieldsClass.class); + + GeneralOptionalReferenceTypeFieldsClass src = new GeneralOptionalReferenceTypeFieldsClass(); + src.f0 = null; + src.f1 = null; + src.f2 = null; + src.f3 = null; + src.f4 = null; + src.f5 = null; + src.f6 = null; + src.f7 = null; + src.f8 = null; + src.f9 = null; + src.f10 = null; + + try { + byte[] raw = MessagePack.pack(src); + GeneralOptionalReferenceTypeFieldsClass dst = MessagePack.unpack( + raw).convert(GeneralOptionalReferenceTypeFieldsClass.class); + assertEquals(src.f0, dst.f0); + assertEquals(src.f1, dst.f1); + assertEquals(src.f2, dst.f2); + assertEquals(src.f3, dst.f3); + assertEquals(src.f4, dst.f4); + assertEquals(src.f5, dst.f5); + assertEquals(src.f6, dst.f6); + assertEquals(src.f7, dst.f7); + assertEquals(src.f8, dst.f8); + assertEquals(src.f9, dst.f9); + assertEquals(src.f10, dst.f10); + } finally { + TemplateRegistry.unregister(GeneralOptionalReferenceTypeFieldsClass.class); + } + } + + @Test + public void testGeneralOptionalReferenceTypeFieldsClass02() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(GeneralOptionalReferenceTypeFieldsClass.class); + + GeneralOptionalReferenceTypeFieldsClass src = null; + + try { + byte[] raw = MessagePack.pack(src); + GeneralOptionalReferenceTypeFieldsClass dst = MessagePack.unpack( + raw).convert(GeneralOptionalReferenceTypeFieldsClass.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(GeneralOptionalReferenceTypeFieldsClass.class); + } + } + + @MessagePackMessage + public static class GeneralOptionalReferenceTypeFieldsClass { + @Optional + public Byte f0; + @Optional + public Short f1; + @Optional + public Integer f2; + @Optional + public Long f3; + @Optional + public Float f4; + @Optional + public Double f5; + @Optional + public Boolean f6; + @Optional + public BigInteger f7; + @Optional + public String f8; + @Optional + public byte[] f9; + @Optional + public ByteBuffer f10; + + public GeneralOptionalReferenceTypeFieldsClass() { + } + } + + @Test + public void testListTypes00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleListNestedType.class); + TemplatePrecompiler.saveTemplateClass(SampleListTypes.class); + + SampleListTypes src = new SampleListTypes(); + src.f0 = new ArrayList(); + src.f1 = new ArrayList(); + src.f1.add(1); + src.f1.add(2); + src.f1.add(3); + src.f2 = new ArrayList(); + src.f2.add("e1"); + src.f2.add("e2"); + src.f2.add("e3"); + src.f3 = new ArrayList>(); + src.f3.add(src.f2); + src.f4 = new ArrayList(); + SampleListNestedType slnt = new SampleListNestedType(); + 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())); + + try { + byte[] raw = MessagePack.pack(src); + SampleListTypes dst = MessagePack.unpack(raw).convert( + SampleListTypes.class); + for (int i = 0; i < src.f1.size(); ++i) { + assertEquals(src.f1.get(i), dst.f1.get(i)); + } + assertEquals(src.f2.size(), dst.f2.size()); + for (int i = 0; i < src.f2.size(); ++i) { + assertEquals(src.f2.get(i), dst.f2.get(i)); + } + assertEquals(src.f3.size(), dst.f3.size()); + for (int i = 0; i < src.f3.size(); ++i) { + List srclist = src.f3.get(i); + List dstlist = dst.f3.get(i); + assertEquals(srclist.size(), dstlist.size()); + for (int j = 0; j < srclist.size(); ++j) { + assertEquals(srclist.get(j), dstlist.get(j)); + } + } + assertEquals(src.f4.size(), dst.f4.size()); + for (int i = 0; i < src.f4.size(); ++i) { + SampleListNestedType s = src.f4.get(i); + SampleListNestedType d = dst.f4.get(i); + assertEquals(s.f0[0], d.f0[0]); + 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); + } + } finally { + TemplateRegistry.unregister(SampleListNestedType.class); + TemplateRegistry.unregister(SampleListTypes.class); + } + } + + @Test + public void testListTypes01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleListNestedType.class); + TemplatePrecompiler.saveTemplateClass(SampleListTypes.class); + + SampleListTypes src = null; + + try { + byte[] raw = MessagePack.pack(src); + SampleListTypes dst = MessagePack.unpack(raw).convert( + SampleListTypes.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(SampleListNestedType.class); + TemplateRegistry.unregister(SampleListTypes.class); + } + } + + @MessagePackMessage + public static class SampleListTypes { + public List f0; + public List f1; + public List f2; + public List> f3; + public List f4; + public List f5; + + public SampleListTypes() { + } + } + + @MessagePackMessage + public static class SampleListNestedType { + public byte[] f0; + public String f1; + + public SampleListNestedType() { + } + } + + @Test + public void testOptionalListTypes00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleOptionalListNestedType.class); + TemplatePrecompiler.saveTemplateClass(SampleOptionalListTypes.class); + + SampleOptionalListTypes src = new SampleOptionalListTypes(); + src.f0 = new ArrayList(); + src.f1 = new ArrayList(); + src.f1.add(1); + src.f1.add(2); + src.f1.add(3); + src.f2 = new ArrayList(); + src.f2.add("e1"); + src.f2.add("e2"); + src.f2.add("e3"); + src.f3 = new ArrayList>(); + src.f3.add(src.f2); + src.f4 = new ArrayList(); + SampleOptionalListNestedType slnt = new SampleOptionalListNestedType(); + 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())); + + try { + byte[] raw = MessagePack.pack(src); + SampleOptionalListTypes dst = MessagePack.unpack(raw).convert( + SampleOptionalListTypes.class); + assertEquals(src.f0.size(), dst.f0.size()); + assertEquals(src.f1.size(), dst.f1.size()); + for (int i = 0; i < src.f1.size(); ++i) { + assertEquals(src.f1.get(i), dst.f1.get(i)); + } + assertEquals(src.f2.size(), dst.f2.size()); + for (int i = 0; i < src.f2.size(); ++i) { + assertEquals(src.f2.get(i), dst.f2.get(i)); + } + assertEquals(src.f3.size(), dst.f3.size()); + for (int i = 0; i < src.f3.size(); ++i) { + List srclist = src.f3.get(i); + List dstlist = dst.f3.get(i); + assertEquals(srclist.size(), dstlist.size()); + for (int j = 0; j < srclist.size(); ++j) { + assertEquals(srclist.get(j), dstlist.get(j)); + } + } + assertEquals(src.f4.size(), dst.f4.size()); + for (int i = 0; i < src.f4.size(); ++i) { + SampleOptionalListNestedType s = src.f4.get(i); + SampleOptionalListNestedType d = dst.f4.get(i); + assertEquals(s.f0[0], d.f0[0]); + 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); + } + } finally { + TemplateRegistry.unregister(SampleOptionalListNestedType.class); + TemplateRegistry.unregister(SampleOptionalListNestedType.class); + } + } + + @Test + public void testOptionalListTypes01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleOptionalListNestedType.class); + TemplatePrecompiler.saveTemplateClass(SampleOptionalListTypes.class); + + SampleOptionalListTypes src = new SampleOptionalListTypes(); + src.f0 = new ArrayList(); + src.f1 = null; + src.f2 = new ArrayList(); + src.f3 = new ArrayList>(); + src.f4 = null; + src.f5 = new ArrayList(); + + try { + byte[] raw = MessagePack.pack(src); + SampleOptionalListTypes dst = MessagePack.unpack(raw).convert( + SampleOptionalListTypes.class); + assertEquals(src.f0.size(), dst.f0.size()); + assertEquals(src.f1, dst.f1); + 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()); + } finally { + TemplateRegistry.unregister(SampleOptionalListNestedType.class); + TemplateRegistry.unregister(SampleOptionalListNestedType.class); + } + } + + @Test + public void testOptionalListTypes02() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleOptionalListNestedType.class); + TemplatePrecompiler.saveTemplateClass(SampleOptionalListTypes.class); + + SampleListTypes src = null; + + try { + byte[] raw = MessagePack.pack(src); + SampleListTypes dst = MessagePack.unpack(raw).convert( + SampleListTypes.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(SampleOptionalListNestedType.class); + TemplateRegistry.unregister(SampleOptionalListNestedType.class); + } + } + + @MessagePackMessage + public static class SampleOptionalListTypes { + @Optional + public List f0; + @Optional + public List f1; + @Optional + public List f2; + @Optional + public List> f3; + @Optional + public List f4; + @Optional + public List f5; + + public SampleOptionalListTypes() { + } + } + + @MessagePackMessage + public static class SampleOptionalListNestedType { + @Optional + public byte[] f0; + @Optional + public String f1; + + public SampleOptionalListNestedType() { + } + } + + @Test + public void testMapTypes00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleMapTypes.class); + + SampleMapTypes src = new SampleMapTypes(); + src.f0 = new HashMap(); + src.f1 = new HashMap(); + src.f1.put(1, 1); + src.f1.put(2, 2); + src.f1.put(3, 3); + src.f2 = new HashMap(); + src.f2.put("k1", 1); + src.f2.put("k2", 2); + src.f2.put("k3", 3); + + try { + byte[] raw = MessagePack.pack(src); + SampleMapTypes dst = MessagePack.unpack(raw).convert( + SampleMapTypes.class); + assertEquals(0, dst.f0.size()); + assertEquals(src.f1.size(), dst.f1.size()); + Iterator srcf1 = src.f1.keySet().iterator(); + while (srcf1.hasNext()) { + Integer s1 = srcf1.next(); + assertEquals(src.f1.get(s1), dst.f1.get(s1)); + } + assertEquals(src.f2.size(), dst.f2.size()); + Iterator srcf2 = src.f2.keySet().iterator(); + while (srcf2.hasNext()) { + String s2 = srcf2.next(); + assertEquals(src.f2.get(s2), dst.f2.get(s2)); + } + } finally { + TemplateRegistry.unregister(SampleMapTypes.class); + } + } + + @Test + public void testMapTypes01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleMapTypes.class); + + SampleMapTypes src = null; + + try { + byte[] raw = MessagePack.pack(src); + SampleMapTypes dst = MessagePack.unpack(raw).convert(SampleMapTypes.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(SampleMapTypes.class); + } + } + + @MessagePackMessage + public static class SampleMapTypes { + public Map f0; + public Map f1; + public Map f2; + + public SampleMapTypes() { + } + } + + @Test + public void testOptionalMapTypes00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleOptionalMapTypes.class); + + SampleOptionalMapTypes src = new SampleOptionalMapTypes(); + src.f0 = new HashMap(); + src.f1 = new HashMap(); + src.f1.put(1, 1); + src.f1.put(2, 2); + src.f1.put(3, 3); + src.f2 = new HashMap(); + src.f2.put("k1", 1); + src.f2.put("k2", 2); + src.f2.put("k3", 3); + + try { + byte[] raw = MessagePack.pack(src); + SampleOptionalMapTypes dst = MessagePack.unpack(raw).convert( + SampleOptionalMapTypes.class); + assertEquals(0, dst.f0.size()); + assertEquals(src.f1.size(), dst.f1.size()); + Iterator srcf1 = src.f1.keySet().iterator(); + while (srcf1.hasNext()) { + Integer s1 = srcf1.next(); + assertEquals(src.f1.get(s1), dst.f1.get(s1)); + } + assertEquals(src.f2.size(), dst.f2.size()); + Iterator srcf2 = src.f2.keySet().iterator(); + while (srcf2.hasNext()) { + String s2 = srcf2.next(); + assertEquals(src.f2.get(s2), dst.f2.get(s2)); + } + } finally { + TemplateRegistry.unregister(SampleOptionalMapTypes.class); + } + } + + @Test + public void testOptionalMapTypes01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleOptionalMapTypes.class); + + SampleOptionalMapTypes src = new SampleOptionalMapTypes(); + src.f0 = new HashMap(); + src.f1 = null; + src.f2 = new HashMap(); + + try { + byte[] raw = MessagePack.pack(src); + SampleOptionalMapTypes dst = MessagePack.unpack(raw).convert( + SampleOptionalMapTypes.class); + assertEquals(src.f0.size(), dst.f0.size()); + assertEquals(src.f1, dst.f1); + assertEquals(src.f2.size(), dst.f2.size()); + } finally { + TemplateRegistry.unregister(SampleOptionalMapTypes.class); + } + } + + @Test + public void testOptionalMapTypes02() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleOptionalMapTypes.class); + + SampleOptionalMapTypes src = null; + + try { + byte[] raw = MessagePack.pack(src); + SampleOptionalMapTypes dst = MessagePack.unpack(raw).convert( + SampleOptionalMapTypes.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(SampleOptionalMapTypes.class); + } + } + + @MessagePackMessage + public static class SampleOptionalMapTypes { + @Optional + public Map f0; + @Optional + public Map f1; + @Optional + public Map f2; + + public SampleOptionalMapTypes() { + } + } + + @Test + public void testFinalClass() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + try { + TemplatePrecompiler.saveTemplateClass(FinalModifierClass.class); + assertTrue(true); + } catch (TemplateBuildException e) { + fail(); + } finally { + TemplateRegistry.unregister(FinalModifierClass.class); + } + } + + @MessagePackMessage + public final static class FinalModifierClass { + } + + @MessagePackMessage + public abstract static class AbstractModifierClass { + } + + @Test + public void testInterfaceType00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + try { + TemplatePrecompiler.saveTemplateClass(SampleInterface.class); + fail(); + } catch (Throwable t) { + assertTrue(t instanceof TemplateBuildException); + } finally { + TemplateRegistry.unregister(SampleInterface.class); + } + } + + @MessagePackMessage + public interface SampleInterface { + } + + @Test + public void testFieldModifiers() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(FieldModifiersClass.class); + + FieldModifiersClass src = new FieldModifiersClass(); + src.f0 = 0; + src.f2 = 2; + src.f3 = 3; + src.f4 = 4; + + try { + byte[] raw = MessagePack.pack(src); + FieldModifiersClass dst = MessagePack.unpack(raw).convert( + FieldModifiersClass.class); + assertTrue(src.f1 == dst.f1); + assertTrue(src.f2 != dst.f2); + assertTrue(src.f3 != dst.f3); + assertTrue(src.f4 != dst.f4); + } finally { + TemplateRegistry.unregister(FieldModifiersClass.class); + } + } + + @MessagePackMessage + public static class FieldModifiersClass { + public int f0; + public final int f1 = 1; + private int f2; + protected int f3; + int f4; + + public FieldModifiersClass() { + } + } + + @Test + public void testOptionalFieldModifiers() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(OptionalFieldModifiersClass.class); + + OptionalFieldModifiersClass src = new OptionalFieldModifiersClass(); + src.f0 = 0; + src.f2 = 2; + src.f3 = 3; + src.f4 = 4; + + try { + byte[] raw = MessagePack.pack(src); + OptionalFieldModifiersClass dst = MessagePack.unpack(raw).convert( + OptionalFieldModifiersClass.class); + assertTrue(src.f0 == dst.f0); + assertTrue(src.f1 == dst.f1); + assertTrue(src.f2 != dst.f2); + assertTrue(src.f3 != dst.f3); + assertTrue(src.f4 != dst.f4); + } finally { + TemplateRegistry.unregister(OptionalFieldModifiersClass.class); + } + } + + @MessagePackMessage + public static class OptionalFieldModifiersClass { + @Optional + public int f0; + @Optional + public final int f1 = 1; + private int f2; + protected int f3; + int f4; + + public OptionalFieldModifiersClass() { + } + } + + @Test + public void testNestedFieldClass00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(NestedClass.class); + TemplatePrecompiler.saveTemplateClass(BaseClass.class); + + BaseClass src = new BaseClass(); + NestedClass src2 = new NestedClass(); + src.f0 = 0; + src2.f2 = 2; + src.f1 = src2; + + try { + byte[] raw = MessagePack.pack(src); + BaseClass dst = MessagePack.unpack(raw).convert(BaseClass.class); + assertTrue(src.f0 == dst.f0); + assertTrue(src.f1.f2 == dst.f1.f2); + } finally { + TemplateRegistry.unregister(NestedClass.class); + TemplateRegistry.unregister(BaseClass.class); + } + } + + @Test + public void testNestedFieldClass01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(NestedClass.class); + TemplatePrecompiler.saveTemplateClass(BaseClass.class); + + BaseClass src = null; + + try { + byte[] raw = MessagePack.pack(src); + BaseClass dst = MessagePack.unpack(raw).convert(BaseClass.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(NestedClass.class); + TemplateRegistry.unregister(BaseClass.class); + } + } + + @MessagePackMessage + public static class BaseClass { + public int f0; + public NestedClass f1; + + public BaseClass() { + } + } + + @MessagePackMessage + public static class NestedClass { + public int f2; + + public NestedClass() { + } + } + + @Test + public void testOptionalNestedFieldClass00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(OptionalNestedClass.class); + TemplatePrecompiler.saveTemplateClass(OptionalBaseClass.class); + + OptionalBaseClass src = new OptionalBaseClass(); + OptionalNestedClass src2 = new OptionalNestedClass(); + src.f0 = 0; + src2.f2 = 2; + src.f1 = src2; + + try { + byte[] raw = MessagePack.pack(src); + OptionalBaseClass dst = MessagePack.unpack(raw).convert( + OptionalBaseClass.class); + assertTrue(src.f0 == dst.f0); + assertTrue(src.f1.f2 == dst.f1.f2); + } finally { + TemplateRegistry.unregister(OptionalNestedClass.class); + TemplateRegistry.unregister(OptionalBaseClass.class); + } + } + + @Test + public void testOptionalNestedFieldClass01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(OptionalNestedClass.class); + TemplatePrecompiler.saveTemplateClass(OptionalBaseClass.class); + + OptionalBaseClass src = new OptionalBaseClass(); + src.f1 = null; + + try { + byte[] raw = MessagePack.pack(src); + OptionalBaseClass dst = MessagePack.unpack(raw).convert( + OptionalBaseClass.class); + assertTrue(src.f0 == dst.f0); + assertTrue(src.f1 == dst.f1); + } finally { + TemplateRegistry.unregister(OptionalNestedClass.class); + TemplateRegistry.unregister(OptionalBaseClass.class); + } + } + + @Test + public void testOptionalNestedFieldClass02() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(OptionalNestedClass.class); + TemplatePrecompiler.saveTemplateClass(OptionalBaseClass.class); + + OptionalBaseClass src = null; + + try { + byte[] raw = MessagePack.pack(src); + OptionalBaseClass dst = MessagePack.unpack(raw).convert( + OptionalBaseClass.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(OptionalNestedClass.class); + TemplateRegistry.unregister(OptionalBaseClass.class); + } + } + + @MessagePackMessage + public static class OptionalBaseClass { + @Optional + public int f0; + @Optional + public OptionalNestedClass f1; + + public OptionalBaseClass() { + } + } + + @MessagePackMessage + public static class OptionalNestedClass { + @Optional + public int f2; + + public OptionalNestedClass() { + } + } + + @Test + public void testMessagePackMessageFieldClass00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(MessagePackMessageClass2.class); + TemplatePrecompiler.saveTemplateClass(BaseClass2.class); + + BaseClass2 src = new BaseClass2(); + MessagePackMessageClass2 src2 = new MessagePackMessageClass2(); + src.f0 = 0; + src2.f2 = 2; + src.f1 = src2; + + try { + byte[] raw = MessagePack.pack(src); + BaseClass2 dst = MessagePack.unpack(raw).convert(BaseClass2.class); + assertTrue(src.f0 == dst.f0); + assertTrue(src.f1.f2 == dst.f1.f2); + } finally { + TemplateRegistry.unregister(MessagePackMessageClass2.class); + TemplateRegistry.unregister(BaseClass2.class); + } + } + + @Test + public void testMessagePackMessageFieldClass01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(MessagePackMessageClass2.class); + TemplatePrecompiler.saveTemplateClass(BaseClass2.class); + + BaseClass2 src = null; + + try { + byte[] raw = MessagePack.pack(src); + BaseClass2 dst = MessagePack.unpack(raw).convert(BaseClass2.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(MessagePackMessageClass2.class); + TemplateRegistry.unregister(BaseClass2.class); + } + } + + @MessagePackMessage + public static class BaseClass2 { + public int f0; + public MessagePackMessageClass2 f1; + + public BaseClass2() { + } + } + + @MessagePackMessage + public static class MessagePackMessageClass2 { + public int f2; + + public MessagePackMessageClass2() { + } + } + + @Test + public void testOptionalMessagePackMessageFieldClass00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(OptionalBaseClass2.class); + TemplatePrecompiler.saveTemplateClass(OptionalMessagePackMessageClass2.class); + + OptionalBaseClass2 src = new OptionalBaseClass2(); + OptionalMessagePackMessageClass2 src2 = new OptionalMessagePackMessageClass2(); + src.f0 = 0; + src2.f2 = 2; + src.f1 = src2; + + try { + byte[] raw = MessagePack.pack(src); + OptionalBaseClass2 dst = MessagePack.unpack(raw).convert( + OptionalBaseClass2.class); + assertTrue(src.f0 == dst.f0); + assertTrue(src.f1.f2 == dst.f1.f2); + } finally { + TemplateRegistry.unregister(OptionalBaseClass2.class); + TemplateRegistry.unregister(OptionalMessagePackMessageClass2.class); + } + } + + @Test + public void testOptionalMessagePackMessageFieldClass01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(OptionalBaseClass2.class); + TemplatePrecompiler.saveTemplateClass(OptionalMessagePackMessageClass2.class); + + OptionalBaseClass2 src = new OptionalBaseClass2(); + src.f1 = null; + + try { + byte[] raw = MessagePack.pack(src); + OptionalBaseClass2 dst = MessagePack.unpack(raw).convert( + OptionalBaseClass2.class); + assertTrue(src.f0 == dst.f0); + assertEquals(src.f1, dst.f1); + } finally { + TemplateRegistry.unregister(OptionalBaseClass2.class); + TemplateRegistry.unregister(OptionalMessagePackMessageClass2.class); + } + } + + @Test + public void testOptionalMessagePackMessageFieldClass02() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(OptionalBaseClass2.class); + TemplatePrecompiler.saveTemplateClass(OptionalMessagePackMessageClass2.class); + + OptionalBaseClass2 src = null; + + try { + byte[] raw = MessagePack.pack(src); + OptionalBaseClass2 dst = MessagePack.unpack(raw).convert( + OptionalBaseClass2.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(OptionalBaseClass2.class); + TemplateRegistry.unregister(OptionalMessagePackMessageClass2.class); + } + } + + @MessagePackMessage + public static class OptionalBaseClass2 { + @Optional + public int f0; + @Optional + public OptionalMessagePackMessageClass2 f1; + + public OptionalBaseClass2() { + } + } + + @MessagePackMessage + public static class OptionalMessagePackMessageClass2 { + @Optional + public int f2; + + public OptionalMessagePackMessageClass2() { + } + } + + @Test + public void testExtendedClass00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleSuperClass.class); + TemplatePrecompiler.saveTemplateClass(SampleSubClass.class); + + SampleSubClass src = new SampleSubClass(); + src.f0 = 0; + src.f2 = 2; + src.f3 = 3; + src.f4 = 4; + src.f5 = 5; + src.f8 = 8; + src.f9 = 9; + + try { + byte[] raw = MessagePack.pack(src); + SampleSubClass dst = MessagePack.unpack(raw).convert( + SampleSubClass.class); + assertTrue(src.f0 == dst.f0); + assertTrue(src.f1 == dst.f1); + assertTrue(src.f2 != dst.f2); + assertTrue(src.f3 != dst.f3); + assertTrue(src.f4 != dst.f4); + assertTrue(src.f5 == dst.f5); + assertTrue(src.f6 == dst.f6); + assertTrue(src.f8 != dst.f8); + assertTrue(src.f9 != dst.f9); + } finally { + TemplateRegistry.unregister(SampleSuperClass.class); + TemplateRegistry.unregister(SampleSubClass.class); + } + } + + @Test + public void testExtendedClass01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleSuperClass.class); + TemplatePrecompiler.saveTemplateClass(SampleSubClass.class); + + SampleSubClass src = null; + + try { + byte[] raw = MessagePack.pack(src); + SampleSubClass dst = MessagePack.unpack(raw).convert( + SampleSubClass.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(SampleSuperClass.class); + TemplateRegistry.unregister(SampleSubClass.class); + } + } + + @MessagePackMessage + public static class SampleSubClass extends SampleSuperClass { + public int f0; + public final int f1 = 1; + private int f2; + protected int f3; + int f4; + + public SampleSubClass() { + } + } + + @MessagePackMessage + public static class SampleSuperClass { + public int f5; + public final int f6 = 2; + @SuppressWarnings("unused") + private int f7; + protected int f8; + int f9; + + public SampleSuperClass() { + } + } + + @Test + public void testOptionalExtendedClass00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleOptionalSuperClass.class); + TemplatePrecompiler.saveTemplateClass(SampleOptionalSubClass.class); + + SampleOptionalSubClass src = new SampleOptionalSubClass(); + src.f0 = 0; + src.f2 = 2; + src.f3 = 3; + src.f4 = 4; + src.f5 = 5; + src.f8 = 8; + src.f9 = 9; + + try { + byte[] raw = MessagePack.pack(src); + SampleOptionalSubClass dst = MessagePack.unpack(raw).convert( + SampleOptionalSubClass.class); + assertTrue(src.f0 == dst.f0); + assertTrue(src.f1 == dst.f1); + assertTrue(src.f2 != dst.f2); + assertTrue(src.f3 != dst.f3); + assertTrue(src.f4 != dst.f4); + assertTrue(src.f5 == dst.f5); + assertTrue(src.f6 == dst.f6); + assertTrue(src.f8 != dst.f8); + assertTrue(src.f9 != dst.f9); + } finally { + TemplateRegistry.unregister(SampleOptionalSuperClass.class); + TemplateRegistry.unregister(SampleOptionalSubClass.class); + } + } + + @Test + public void testOptionalExtendedClass01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleOptionalSuperClass.class); + TemplatePrecompiler.saveTemplateClass(SampleOptionalSubClass.class); + + SampleOptionalSubClass src = null; + + try { + byte[] raw = MessagePack.pack(src); + SampleOptionalSubClass dst = MessagePack.unpack(raw).convert( + SampleOptionalSubClass.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(SampleOptionalSuperClass.class); + TemplateRegistry.unregister(SampleOptionalSubClass.class); + } + } + + @MessagePackMessage + public static class SampleOptionalSubClass extends SampleOptionalSuperClass { + @Optional + public int f0; + public final int f1 = 1; + private int f2; + protected int f3; + int f4; + + public SampleOptionalSubClass() { + } + } + + @MessagePackMessage + public static class SampleOptionalSuperClass { + @Optional + public int f5; + public final int f6 = 2; + @SuppressWarnings("unused") + private int f7; + protected int f8; + int f9; + + public SampleOptionalSuperClass() { + } + } +} diff --git a/java/src/test/java/org/msgpack/util/TestTemplatePrecompilerPackUnpack.java b/java/src/test/java/org/msgpack/util/TestTemplatePrecompilerPackUnpack.java new file mode 100644 index 00000000..7b0a7885 --- /dev/null +++ b/java/src/test/java/org/msgpack/util/TestTemplatePrecompilerPackUnpack.java @@ -0,0 +1,1422 @@ +package org.msgpack.util; + +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import junit.framework.TestCase; + +import org.junit.Test; +import org.msgpack.MessagePack; +import org.msgpack.annotation.MessagePackMessage; +import org.msgpack.annotation.Optional; +import org.msgpack.template.TemplateBuildException; +import org.msgpack.template.TemplateRegistry; + +public class TestTemplatePrecompilerPackUnpack extends TestCase { + + @Test + public void testPrimitiveTypeFields00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + Class c = PrimitiveTypeFieldsClass.class; + TemplatePrecompiler.saveTemplateClass(PrimitiveTypeFieldsClass.class); + + PrimitiveTypeFieldsClass src = new PrimitiveTypeFieldsClass(); + src.f0 = (byte) 0; + src.f1 = 1; + src.f2 = 2; + src.f3 = 3; + src.f4 = 4; + src.f5 = 5; + src.f6 = false; + + try { + TemplateRegistry.unregister(c); + TemplateRegistry.lookup(c); + byte[] raw = MessagePack.pack(src); + PrimitiveTypeFieldsClass dst = MessagePack.unpack(raw, PrimitiveTypeFieldsClass.class); + assertEquals(src.f0, dst.f0); + assertEquals(src.f1, dst.f1); + assertEquals(src.f2, dst.f2); + assertEquals(src.f3, dst.f3); + assertEquals(src.f4, dst.f4); + assertEquals(src.f5, dst.f5); + assertEquals(src.f6, dst.f6); + } finally { + TemplateRegistry.unregister(c); + } + } + + @Test + public void testPrimitiveTypeFields01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + Class c = PrimitiveTypeFieldsClass.class; + TemplatePrecompiler.saveTemplateClass(PrimitiveTypeFieldsClass.class); + + PrimitiveTypeFieldsClass src = new PrimitiveTypeFieldsClass(); + + try { + TemplateRegistry.unregister(c); + TemplateRegistry.lookup(c); + byte[] raw = MessagePack.pack(src); + PrimitiveTypeFieldsClass dst = MessagePack.unpack(raw, PrimitiveTypeFieldsClass.class); + assertEquals(src.f0, dst.f0); + assertEquals(src.f1, dst.f1); + assertEquals(src.f2, dst.f2); + assertEquals(src.f3, dst.f3); + assertEquals(src.f4, dst.f4); + assertEquals(src.f5, dst.f5); + assertEquals(src.f6, dst.f6); + } finally { + TemplateRegistry.unregister(c); + } + } + + @Test + public void testPrimitiveTypeFields02() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + Class c = PrimitiveTypeFieldsClass.class; + TemplatePrecompiler.saveTemplateClass(PrimitiveTypeFieldsClass.class); + + PrimitiveTypeFieldsClass src = null; + + try { + TemplateRegistry.unregister(c); + TemplateRegistry.lookup(c); + byte[] raw = MessagePack.pack(src); + PrimitiveTypeFieldsClass dst = MessagePack.unpack(raw, PrimitiveTypeFieldsClass.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(c); + } + } + + @MessagePackMessage + public static class PrimitiveTypeFieldsClass { + public byte f0; + public short f1; + public int f2; + public long f3; + public float f4; + public double f5; + public boolean f6; + + public PrimitiveTypeFieldsClass() { + } + } + + @Test + public void testOptionalPrimitiveTypeFields00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + Class c = OptionalPrimitiveTypeFieldsClass.class; + TemplatePrecompiler.saveTemplateClass(OptionalPrimitiveTypeFieldsClass.class); + + OptionalPrimitiveTypeFieldsClass src = new OptionalPrimitiveTypeFieldsClass(); + src.f0 = (byte) 0; + src.f1 = 1; + src.f2 = 2; + src.f3 = 3; + src.f4 = 4; + src.f5 = 5; + src.f6 = false; + + try { + TemplateRegistry.unregister(c); + TemplateRegistry.lookup(c); + byte[] raw = MessagePack.pack(src); + OptionalPrimitiveTypeFieldsClass dst = + MessagePack.unpack(raw, OptionalPrimitiveTypeFieldsClass.class); + assertEquals(src.f0, dst.f0); + assertEquals(src.f1, dst.f1); + assertEquals(src.f2, dst.f2); + assertEquals(src.f3, dst.f3); + assertEquals(src.f4, dst.f4); + assertEquals(src.f5, dst.f5); + assertEquals(src.f6, dst.f6); + } finally { + TemplateRegistry.unregister(c); + } + } + + @Test + public void testOptionalPrimitiveTypeFields01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + Class c = OptionalPrimitiveTypeFieldsClass.class; + TemplatePrecompiler.saveTemplateClass(c); + + OptionalPrimitiveTypeFieldsClass src = new OptionalPrimitiveTypeFieldsClass(); + + try { + TemplateRegistry.unregister(c); + TemplateRegistry.lookup(c); + byte[] raw = MessagePack.pack(src); + OptionalPrimitiveTypeFieldsClass dst = + MessagePack.unpack(raw, OptionalPrimitiveTypeFieldsClass.class); + assertEquals(src.f0, dst.f0); + assertEquals(src.f1, dst.f1); + assertEquals(src.f2, dst.f2); + assertEquals(src.f3, dst.f3); + assertEquals(src.f4, dst.f4); + assertEquals(src.f5, dst.f5); + assertEquals(src.f6, dst.f6); + } finally { + TemplateRegistry.unregister(c); + } + } + + @Test + public void testOptionalPrimitiveTypeFields02() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + Class c = OptionalPrimitiveTypeFieldsClass.class; + TemplatePrecompiler.saveTemplateClass(c); + + OptionalPrimitiveTypeFieldsClass src = null; + + try { + TemplateRegistry.unregister(c); + TemplateRegistry.lookup(c); + byte[] raw = MessagePack.pack(src); + OptionalPrimitiveTypeFieldsClass dst = + MessagePack.unpack(raw, OptionalPrimitiveTypeFieldsClass.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(c); + } + } + + @MessagePackMessage + public static class OptionalPrimitiveTypeFieldsClass { + @Optional + public byte f0; + @Optional + public short f1; + @Optional + public int f2; + @Optional + public long f3; + @Optional + public float f4; + @Optional + public double f5; + @Optional + public boolean f6; + + public OptionalPrimitiveTypeFieldsClass() { + } + } + + @Test + public void testGeneralReferenceTypeFieldsClass00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + Class c = GeneralReferenceTypeFieldsClass.class; + TemplatePrecompiler.saveTemplateClass(c); + + GeneralReferenceTypeFieldsClass src = new GeneralReferenceTypeFieldsClass(); + src.f0 = 0; + src.f1 = 1; + src.f2 = 2; + src.f3 = (long) 3; + src.f4 = (float) 4; + src.f5 = (double) 5; + src.f6 = false; + src.f7 = new BigInteger("7"); + src.f8 = "8"; + src.f9 = new byte[] { 0x01, 0x02 }; + src.f10 = ByteBuffer.wrap("muga".getBytes()); + + try { + TemplateRegistry.unregister(c); + TemplateRegistry.lookup(c); + byte[] raw = MessagePack.pack(src); + GeneralReferenceTypeFieldsClass dst = + MessagePack.unpack(raw, GeneralReferenceTypeFieldsClass.class); + assertEquals(src.f0, dst.f0); + assertEquals(src.f1, dst.f1); + assertEquals(src.f2, dst.f2); + assertEquals(src.f3, dst.f3); + assertEquals(src.f4, dst.f4); + assertEquals(src.f5, dst.f5); + assertEquals(src.f6, dst.f6); + assertEquals(src.f7, dst.f7); + assertEquals(src.f8, dst.f8); + assertEquals(src.f9[0], dst.f9[0]); + assertEquals(src.f9[1], dst.f9[1]); + assertEquals(src.f10, dst.f10); + } finally { + TemplateRegistry.unregister(c); + } + } + + @Test + public void testGeneralReferenceTypeFieldsClass01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + Class c = GeneralReferenceTypeFieldsClass.class; + TemplatePrecompiler.saveTemplateClass(c); + + GeneralReferenceTypeFieldsClass src = null; + + try { + TemplateRegistry.unregister(c); + TemplateRegistry.lookup(c); + byte[] raw = MessagePack.pack(src); + GeneralReferenceTypeFieldsClass dst = + MessagePack.unpack(raw, GeneralReferenceTypeFieldsClass.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(c); + } + } + + @MessagePackMessage + public static class GeneralReferenceTypeFieldsClass { + public Byte f0; + public Short f1; + public Integer f2; + public Long f3; + public Float f4; + public Double f5; + public Boolean f6; + public BigInteger f7; + public String f8; + public byte[] f9; + public ByteBuffer f10; + + public GeneralReferenceTypeFieldsClass() { + } + } + + @Test + public void testGeneralOptionalReferenceTypeFieldsClass00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + Class c = GeneralOptionalReferenceTypeFieldsClass.class; + TemplatePrecompiler.saveTemplateClass(c); + + GeneralOptionalReferenceTypeFieldsClass src = new GeneralOptionalReferenceTypeFieldsClass(); + src.f0 = 0; + src.f1 = 1; + src.f2 = 2; + src.f3 = (long) 3; + src.f4 = (float) 4; + src.f5 = (double) 5; + src.f6 = false; + src.f7 = new BigInteger("7"); + src.f8 = "8"; + src.f9 = new byte[] { 0x01, 0x02 }; + src.f10 = ByteBuffer.wrap("muga".getBytes()); + + try { + TemplateRegistry.unregister(c); + TemplateRegistry.lookup(c); + byte[] raw = MessagePack.pack(src); + GeneralOptionalReferenceTypeFieldsClass dst = + MessagePack.unpack(raw, GeneralOptionalReferenceTypeFieldsClass.class); + assertEquals(src.f0, dst.f0); + assertEquals(src.f1, dst.f1); + assertEquals(src.f2, dst.f2); + assertEquals(src.f3, dst.f3); + assertEquals(src.f4, dst.f4); + assertEquals(src.f5, dst.f5); + assertEquals(src.f6, dst.f6); + assertEquals(src.f7, dst.f7); + assertEquals(src.f8, dst.f8); + assertEquals(src.f9[0], dst.f9[0]); + assertEquals(src.f9[1], dst.f9[1]); + assertEquals(src.f10, dst.f10); + } finally { + TemplateRegistry.unregister(c); + } + } + + @Test + public void testGeneralOptionalReferenceTypeFieldsClass01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + Class c = GeneralOptionalReferenceTypeFieldsClass.class; + TemplatePrecompiler.saveTemplateClass(c); + + GeneralOptionalReferenceTypeFieldsClass src = new GeneralOptionalReferenceTypeFieldsClass(); + src.f0 = null; + src.f1 = null; + src.f2 = null; + src.f3 = null; + src.f4 = null; + src.f5 = null; + src.f6 = null; + src.f7 = null; + src.f8 = null; + src.f9 = null; + src.f10 = null; + + try { + TemplateRegistry.unregister(c); + TemplateRegistry.lookup(c); + byte[] raw = MessagePack.pack(src); + GeneralOptionalReferenceTypeFieldsClass dst = + MessagePack.unpack(raw, GeneralOptionalReferenceTypeFieldsClass.class); + assertEquals(src.f0, dst.f0); + assertEquals(src.f1, dst.f1); + assertEquals(src.f2, dst.f2); + assertEquals(src.f3, dst.f3); + assertEquals(src.f4, dst.f4); + assertEquals(src.f5, dst.f5); + assertEquals(src.f6, dst.f6); + assertEquals(src.f7, dst.f7); + assertEquals(src.f8, dst.f8); + assertEquals(src.f9, dst.f9); + assertEquals(src.f10, dst.f10); + } finally { + TemplateRegistry.unregister(c); + } + } + + @Test + public void testGeneralOptionalReferenceTypeFieldsClass02() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + Class c = GeneralOptionalReferenceTypeFieldsClass.class; + TemplatePrecompiler.saveTemplateClass(c); + + GeneralOptionalReferenceTypeFieldsClass src = null; + + try { + TemplateRegistry.unregister(c); + TemplateRegistry.lookup(c); + byte[] raw = MessagePack.pack(src); + GeneralOptionalReferenceTypeFieldsClass dst = + MessagePack.unpack(raw, GeneralOptionalReferenceTypeFieldsClass.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(c); + } + } + + @MessagePackMessage + public static class GeneralOptionalReferenceTypeFieldsClass { + @Optional + public Byte f0; + @Optional + public Short f1; + @Optional + public Integer f2; + @Optional + public Long f3; + @Optional + public Float f4; + @Optional + public Double f5; + @Optional + public Boolean f6; + @Optional + public BigInteger f7; + @Optional + public String f8; + @Optional + public byte[] f9; + @Optional + public ByteBuffer f10; + + public GeneralOptionalReferenceTypeFieldsClass() { + } + } + + @Test + public void testListTypes00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleListNestedType.class); + TemplatePrecompiler.saveTemplateClass(SampleListTypes.class); + + SampleListTypes src = new SampleListTypes(); + src.f0 = new ArrayList(); + src.f1 = new ArrayList(); + src.f1.add(1); + src.f1.add(2); + src.f1.add(3); + src.f2 = new ArrayList(); + src.f2.add("e1"); + src.f2.add("e2"); + src.f2.add("e3"); + src.f3 = new ArrayList>(); + src.f3.add(src.f2); + src.f4 = new ArrayList(); + SampleListNestedType slnt = new SampleListNestedType(); + 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())); + + try { + TemplateRegistry.unregister(SampleListNestedType.class); + TemplateRegistry.unregister(SampleListTypes.class); + TemplateRegistry.lookup(SampleListNestedType.class); + TemplateRegistry.lookup(SampleListTypes.class); + + byte[] raw = MessagePack.pack(src); + + SampleListTypes dst = MessagePack + .unpack(raw, SampleListTypes.class); + for (int i = 0; i < src.f1.size(); ++i) { + assertEquals(src.f1.get(i), dst.f1.get(i)); + } + assertEquals(src.f2.size(), dst.f2.size()); + for (int i = 0; i < src.f2.size(); ++i) { + assertEquals(src.f2.get(i), dst.f2.get(i)); + } + assertEquals(src.f3.size(), dst.f3.size()); + for (int i = 0; i < src.f3.size(); ++i) { + List srclist = src.f3.get(i); + List dstlist = dst.f3.get(i); + assertEquals(srclist.size(), dstlist.size()); + for (int j = 0; j < srclist.size(); ++j) { + assertEquals(srclist.get(j), dstlist.get(j)); + } + } + assertEquals(src.f4.size(), dst.f4.size()); + for (int i = 0; i < src.f4.size(); ++i) { + SampleListNestedType s = src.f4.get(i); + SampleListNestedType d = dst.f4.get(i); + assertEquals(s.f0[0], d.f0[0]); + 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); + } + } finally { + TemplateRegistry.unregister(SampleListNestedType.class); + TemplateRegistry.unregister(SampleListTypes.class); + } + } + + @Test + public void testListTypes01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleListNestedType.class); + TemplatePrecompiler.saveTemplateClass(SampleListTypes.class); + + SampleListTypes src = null; + + try { + TemplateRegistry.unregister(SampleListNestedType.class); + TemplateRegistry.unregister(SampleListTypes.class); + TemplateRegistry.lookup(SampleListNestedType.class); + TemplateRegistry.lookup(SampleListTypes.class); + + byte[] raw = MessagePack.pack(src); + + SampleListTypes dst = + MessagePack.unpack(raw, SampleListTypes.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(SampleListNestedType.class); + TemplateRegistry.unregister(SampleListTypes.class); + } + } + + @MessagePackMessage + public static class SampleListTypes { + public List f0; + public List f1; + public List f2; + public List> f3; + public List f4; + public List f5; + + public SampleListTypes() { + } + } + + @MessagePackMessage + public static class SampleListNestedType { + public byte[] f0; + public String f1; + + public SampleListNestedType() { + } + } + + @Test + public void testOptionalListTypes00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleOptionalListNestedType.class); + TemplatePrecompiler.saveTemplateClass(SampleOptionalListTypes.class); + + SampleOptionalListTypes src = new SampleOptionalListTypes(); + src.f0 = new ArrayList(); + src.f1 = new ArrayList(); + src.f1.add(1); + src.f1.add(2); + src.f1.add(3); + src.f2 = new ArrayList(); + src.f2.add("e1"); + src.f2.add("e2"); + src.f2.add("e3"); + src.f3 = new ArrayList>(); + src.f3.add(src.f2); + src.f4 = new ArrayList(); + SampleOptionalListNestedType slnt = new SampleOptionalListNestedType(); + 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())); + + try { + TemplateRegistry.unregister(SampleOptionalListNestedType.class); + TemplateRegistry.unregister(SampleOptionalListTypes.class); + TemplateRegistry.lookup(SampleOptionalListNestedType.class); + TemplateRegistry.lookup(SampleOptionalListTypes.class); + + byte[] raw = MessagePack.pack(src); + + SampleOptionalListTypes dst = MessagePack.unpack(raw, SampleOptionalListTypes.class); + assertEquals(src.f0.size(), dst.f0.size()); + assertEquals(src.f1.size(), dst.f1.size()); + for (int i = 0; i < src.f1.size(); ++i) { + assertEquals(src.f1.get(i), dst.f1.get(i)); + } + assertEquals(src.f2.size(), dst.f2.size()); + for (int i = 0; i < src.f2.size(); ++i) { + assertEquals(src.f2.get(i), dst.f2.get(i)); + } + assertEquals(src.f3.size(), dst.f3.size()); + for (int i = 0; i < src.f3.size(); ++i) { + List srclist = src.f3.get(i); + List dstlist = dst.f3.get(i); + assertEquals(srclist.size(), dstlist.size()); + for (int j = 0; j < srclist.size(); ++j) { + assertEquals(srclist.get(j), dstlist.get(j)); + } + } + assertEquals(src.f4.size(), dst.f4.size()); + for (int i = 0; i < src.f4.size(); ++i) { + SampleOptionalListNestedType s = src.f4.get(i); + SampleOptionalListNestedType d = dst.f4.get(i); + assertEquals(s.f0[0], d.f0[0]); + 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); + } + } finally { + TemplateRegistry.unregister(SampleOptionalListNestedType.class); + TemplateRegistry.unregister(SampleOptionalListTypes.class); + } + } + + @Test + public void testOptionalListTypes01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleOptionalListNestedType.class); + TemplatePrecompiler.saveTemplateClass(SampleOptionalListTypes.class); + + SampleOptionalListTypes src = new SampleOptionalListTypes(); + src.f0 = new ArrayList(); + src.f1 = null; + src.f2 = new ArrayList(); + src.f3 = new ArrayList>(); + src.f4 = null; + src.f5 = new ArrayList(); + + try { + TemplateRegistry.unregister(SampleOptionalListNestedType.class); + TemplateRegistry.unregister(SampleOptionalListTypes.class); + TemplateRegistry.lookup(SampleOptionalListNestedType.class); + TemplateRegistry.lookup(SampleOptionalListTypes.class); + + byte[] raw = MessagePack.pack(src); + SampleOptionalListTypes dst = MessagePack.unpack(raw, SampleOptionalListTypes.class); + assertEquals(src.f0.size(), dst.f0.size()); + assertEquals(src.f1, dst.f1); + 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()); + } finally { + TemplateRegistry.unregister(SampleOptionalListNestedType.class); + TemplateRegistry.unregister(SampleOptionalListTypes.class); + } + } + + @Test + public void testOptionalListTypes02() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleOptionalListNestedType.class); + TemplatePrecompiler.saveTemplateClass(SampleOptionalListTypes.class); + + SampleListTypes src = null; + + try { + TemplateRegistry.unregister(SampleOptionalListNestedType.class); + TemplateRegistry.unregister(SampleOptionalListTypes.class); + TemplateRegistry.lookup(SampleOptionalListNestedType.class); + TemplateRegistry.lookup(SampleOptionalListTypes.class); + + byte[] raw = MessagePack.pack(src); + + SampleListTypes dst = + MessagePack.unpack(raw, SampleListTypes.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(SampleOptionalListNestedType.class); + TemplateRegistry.unregister(SampleOptionalListTypes.class); + } + } + + @MessagePackMessage + public static class SampleOptionalListTypes { + @Optional + public List f0; + @Optional + public List f1; + @Optional + public List f2; + @Optional + public List> f3; + @Optional + public List f4; + @Optional + public List f5; + + public SampleOptionalListTypes() { + } + } + + @MessagePackMessage + public static class SampleOptionalListNestedType { + @Optional + public byte[] f0; + @Optional + public String f1; + + public SampleOptionalListNestedType() { + } + } + + @Test + public void testMapTypes00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleMapTypes.class); + + SampleMapTypes src = new SampleMapTypes(); + src.f0 = new HashMap(); + src.f1 = new HashMap(); + src.f1.put(1, 1); + src.f1.put(2, 2); + src.f1.put(3, 3); + src.f2 = new HashMap(); + src.f2.put("k1", 1); + src.f2.put("k2", 2); + src.f2.put("k3", 3); + + try { + TemplateRegistry.unregister(SampleMapTypes.class); + TemplateRegistry.lookup(SampleMapTypes.class); + + byte[] raw = MessagePack.pack(src); + + SampleMapTypes dst = MessagePack.unpack(raw, SampleMapTypes.class); + assertEquals(0, dst.f0.size()); + assertEquals(src.f1.size(), dst.f1.size()); + Iterator srcf1 = src.f1.keySet().iterator(); + while (srcf1.hasNext()) { + Integer s1 = srcf1.next(); + assertEquals(src.f1.get(s1), dst.f1.get(s1)); + } + assertEquals(src.f2.size(), dst.f2.size()); + Iterator srcf2 = src.f2.keySet().iterator(); + while (srcf2.hasNext()) { + String s2 = srcf2.next(); + assertEquals(src.f2.get(s2), dst.f2.get(s2)); + } + } finally { + TemplateRegistry.unregister(SampleMapTypes.class); + } + } + + @Test + public void testMapTypes01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleMapTypes.class); + + SampleMapTypes src = null; + + try { + TemplateRegistry.unregister(SampleMapTypes.class); + TemplateRegistry.lookup(SampleMapTypes.class); + + byte[] raw = MessagePack.pack(src); + + SampleMapTypes dst = MessagePack.unpack(raw, SampleMapTypes.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(SampleMapTypes.class); + } + } + + @MessagePackMessage + public static class SampleMapTypes { + public Map f0; + public Map f1; + public Map f2; + + public SampleMapTypes() { + } + } + + @Test + public void testOptionalMapTypes00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleOptionalMapTypes.class); + + SampleOptionalMapTypes src = new SampleOptionalMapTypes(); + src.f0 = new HashMap(); + src.f1 = new HashMap(); + src.f1.put(1, 1); + src.f1.put(2, 2); + src.f1.put(3, 3); + src.f2 = new HashMap(); + src.f2.put("k1", 1); + src.f2.put("k2", 2); + src.f2.put("k3", 3); + + try { + TemplateRegistry.unregister(SampleOptionalMapTypes.class); + TemplateRegistry.lookup(SampleOptionalMapTypes.class); + + byte[] raw = MessagePack.pack(src); + + SampleOptionalMapTypes dst = MessagePack.unpack(raw, + SampleOptionalMapTypes.class); + assertEquals(0, dst.f0.size()); + assertEquals(src.f1.size(), dst.f1.size()); + Iterator srcf1 = src.f1.keySet().iterator(); + while (srcf1.hasNext()) { + Integer s1 = srcf1.next(); + assertEquals(src.f1.get(s1), dst.f1.get(s1)); + } + assertEquals(src.f2.size(), dst.f2.size()); + Iterator srcf2 = src.f2.keySet().iterator(); + while (srcf2.hasNext()) { + String s2 = srcf2.next(); + assertEquals(src.f2.get(s2), dst.f2.get(s2)); + } + } finally { + TemplateRegistry.unregister(SampleOptionalMapTypes.class); + } + } + + @Test + public void testOptionalMapTypes01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleOptionalMapTypes.class); + + SampleOptionalMapTypes src = new SampleOptionalMapTypes(); + src.f0 = new HashMap(); + src.f1 = null; + src.f2 = new HashMap(); + + try { + TemplateRegistry.unregister(SampleOptionalMapTypes.class); + TemplateRegistry.lookup(SampleOptionalMapTypes.class); + byte[] raw = MessagePack.pack(src); + + SampleOptionalMapTypes dst = MessagePack.unpack(raw, + SampleOptionalMapTypes.class); + assertEquals(src.f0.size(), dst.f0.size()); + assertEquals(src.f1, dst.f1); + assertEquals(src.f2.size(), dst.f2.size()); + } finally { + TemplateRegistry.unregister(SampleOptionalMapTypes.class); + } + } + + @Test + public void testOptionalMapTypes02() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleOptionalMapTypes.class); + + SampleOptionalMapTypes src = null; + try { + TemplateRegistry.unregister(SampleOptionalMapTypes.class); + TemplateRegistry.lookup(SampleOptionalMapTypes.class); + byte[] raw = MessagePack.pack(src); + + SampleOptionalMapTypes dst = MessagePack.unpack(raw, + SampleOptionalMapTypes.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(SampleOptionalMapTypes.class); + } + } + + @MessagePackMessage + public static class SampleOptionalMapTypes { + @Optional + public Map f0; + @Optional + public Map f1; + @Optional + public Map f2; + + public SampleOptionalMapTypes() { + } + } + + @Test + public void testFinalClass() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + try { + TemplatePrecompiler.saveTemplateClass(FinalModifierClass.class); + assertTrue(true); + } catch (TemplateBuildException e) { + fail(); + } finally { + TemplateRegistry.unregister(FinalModifierClass.class); + } + } + + @MessagePackMessage + public final static class FinalModifierClass { + } + + @MessagePackMessage + public abstract static class AbstractModifierClass { + } + + @Test + public void testInterfaceType00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + try { + TemplatePrecompiler.saveTemplateClass(SampleInterface.class); + fail(); + } catch (Throwable t) { + assertTrue(t instanceof TemplateBuildException); + } finally { + TemplateRegistry.unregister(SampleInterface.class); + } + } + + @MessagePackMessage + public interface SampleInterface { + } + + @Test + public void testFieldModifiers() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(FieldModifiersClass.class); + FieldModifiersClass src = new FieldModifiersClass(); + src.f0 = 0; + src.f2 = 2; + src.f3 = 3; + src.f4 = 4; + + try { + byte[] raw = MessagePack.pack(src); + FieldModifiersClass dst = MessagePack.unpack(raw, FieldModifiersClass.class); + assertTrue(src.f1 == dst.f1); + assertTrue(src.f2 != dst.f2); + assertTrue(src.f3 != dst.f3); + assertTrue(src.f4 != dst.f4); + } finally { + TemplateRegistry.unregister(FieldModifiersClass.class); + } + } + + @MessagePackMessage + public static class FieldModifiersClass { + public int f0; + public final int f1 = 1; + private int f2; + protected int f3; + int f4; + + public FieldModifiersClass() { + } + } + + @Test + public void testOptionalFieldModifiers() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(OptionalFieldModifiersClass.class); + + OptionalFieldModifiersClass src = new OptionalFieldModifiersClass(); + src.f0 = 0; + src.f2 = 2; + src.f3 = 3; + src.f4 = 4; + + try { + byte[] raw = MessagePack.pack(src); + OptionalFieldModifiersClass dst = MessagePack.unpack(raw, + OptionalFieldModifiersClass.class); + assertTrue(src.f0 == dst.f0); + assertTrue(src.f1 == dst.f1); + assertTrue(src.f2 != dst.f2); + assertTrue(src.f3 != dst.f3); + assertTrue(src.f4 != dst.f4); + } finally { + TemplateRegistry.unregister(OptionalFieldModifiersClass.class); + } + } + + @MessagePackMessage + public static class OptionalFieldModifiersClass { + @Optional + public int f0; + @Optional + public final int f1 = 1; + private int f2; + protected int f3; + int f4; + + public OptionalFieldModifiersClass() { + } + } + + @Test + public void testNestedFieldClass00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(NestedClass.class); + TemplatePrecompiler.saveTemplateClass(BaseClass.class); + + BaseClass src = new BaseClass(); + NestedClass src2 = new NestedClass(); + src.f0 = 0; + src2.f2 = 2; + src.f1 = src2; + + try { + byte[] raw = MessagePack.pack(src); + BaseClass dst = MessagePack.unpack(raw, BaseClass.class); + assertTrue(src.f0 == dst.f0); + assertTrue(src.f1.f2 == dst.f1.f2); + } finally { + TemplateRegistry.unregister(NestedClass.class); + TemplateRegistry.unregister(BaseClass.class); + } + } + + @Test + public void testNestedFieldClass01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(NestedClass.class); + TemplatePrecompiler.saveTemplateClass(BaseClass.class); + + BaseClass src = null; + + try { + byte[] raw = MessagePack.pack(src); + BaseClass dst = MessagePack.unpack(raw, BaseClass.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(NestedClass.class); + TemplateRegistry.unregister(BaseClass.class); + } + } + + @MessagePackMessage + public static class BaseClass { + public int f0; + public NestedClass f1; + + public BaseClass() { + } + } + + @MessagePackMessage + public static class NestedClass { + public int f2; + + public NestedClass() { + } + } + + @Test + public void testOptionalNestedFieldClass00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(OptionalNestedClass.class); + TemplatePrecompiler.saveTemplateClass(OptionalBaseClass.class); + + OptionalBaseClass src = new OptionalBaseClass(); + OptionalNestedClass src2 = new OptionalNestedClass(); + src.f0 = 0; + src2.f2 = 2; + src.f1 = src2; + + try { + byte[] raw = MessagePack.pack(src); + OptionalBaseClass dst = MessagePack.unpack(raw, OptionalBaseClass.class); + assertTrue(src.f0 == dst.f0); + assertTrue(src.f1.f2 == dst.f1.f2); + } finally { + TemplateRegistry.unregister(OptionalNestedClass.class); + TemplateRegistry.unregister(OptionalBaseClass.class); + } + } + + @Test + public void testOptionalNestedFieldClass01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(OptionalNestedClass.class); + TemplatePrecompiler.saveTemplateClass(OptionalBaseClass.class); + + OptionalBaseClass src = new OptionalBaseClass(); + src.f1 = null; + + try { + byte[] raw = MessagePack.pack(src); + OptionalBaseClass dst = MessagePack.unpack(raw, + OptionalBaseClass.class); + assertTrue(src.f0 == dst.f0); + assertTrue(src.f1 == dst.f1); + } finally { + TemplateRegistry.unregister(OptionalNestedClass.class); + TemplateRegistry.unregister(OptionalBaseClass.class); + } + } + + @Test + public void testOptionalNestedFieldClass02() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(OptionalNestedClass.class); + TemplatePrecompiler.saveTemplateClass(OptionalBaseClass.class); + + OptionalBaseClass src = null; + + try { + byte[] raw = MessagePack.pack(src); + OptionalBaseClass dst = MessagePack.unpack(raw, OptionalBaseClass.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(OptionalNestedClass.class); + TemplateRegistry.unregister(OptionalBaseClass.class); + } + } + + @MessagePackMessage + public static class OptionalBaseClass { + @Optional + public int f0; + @Optional + public OptionalNestedClass f1; + + public OptionalBaseClass() { + } + } + + @MessagePackMessage + public static class OptionalNestedClass { + @Optional + public int f2; + + public OptionalNestedClass() { + } + } + + @Test + public void testMessagePackMessageFieldClass00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(MessagePackMessageClass2.class); + TemplatePrecompiler.saveTemplateClass(BaseClass2.class); + + BaseClass2 src = new BaseClass2(); + MessagePackMessageClass2 src2 = new MessagePackMessageClass2(); + src.f0 = 0; + src2.f2 = 2; + src.f1 = src2; + + try { + byte[] raw = MessagePack.pack(src); + BaseClass2 dst = MessagePack.unpack(raw, BaseClass2.class); + assertTrue(src.f0 == dst.f0); + assertTrue(src.f1.f2 == dst.f1.f2); + } finally { + TemplateRegistry.unregister(MessagePackMessageClass2.class); + TemplateRegistry.unregister(BaseClass2.class); + } + } + + @Test + public void testMessagePackMessageFieldClass01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(MessagePackMessageClass2.class); + TemplatePrecompiler.saveTemplateClass(BaseClass2.class); + + BaseClass2 src = null; + + try { + byte[] raw = MessagePack.pack(src); + BaseClass2 dst = MessagePack.unpack(raw, BaseClass2.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(MessagePackMessageClass2.class); + TemplateRegistry.unregister(BaseClass2.class); + } + } + + @MessagePackMessage + public static class BaseClass2 { + public int f0; + public MessagePackMessageClass2 f1; + + public BaseClass2() { + } + } + + @MessagePackMessage + public static class MessagePackMessageClass2 { + public int f2; + + public MessagePackMessageClass2() { + } + } + + @Test + public void testOptionalMessagePackMessageFieldClass00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(OptionalBaseClass2.class); + TemplatePrecompiler.saveTemplateClass(OptionalMessagePackMessageClass2.class); + + OptionalBaseClass2 src = new OptionalBaseClass2(); + OptionalMessagePackMessageClass2 src2 = new OptionalMessagePackMessageClass2(); + src.f0 = 0; + src2.f2 = 2; + src.f1 = src2; + + try { + byte[] raw = MessagePack.pack(src); + OptionalBaseClass2 dst = MessagePack.unpack(raw, OptionalBaseClass2.class); + assertTrue(src.f0 == dst.f0); + assertTrue(src.f1.f2 == dst.f1.f2); + } finally { + TemplateRegistry.unregister(OptionalBaseClass2.class); + TemplateRegistry.unregister(OptionalMessagePackMessageClass2.class); + } + } + + @Test + public void testOptionalMessagePackMessageFieldClass01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(OptionalBaseClass2.class); + TemplatePrecompiler.saveTemplateClass(OptionalMessagePackMessageClass2.class); + + OptionalBaseClass2 src = new OptionalBaseClass2(); + src.f1 = null; + + try { + byte[] raw = MessagePack.pack(src); + OptionalBaseClass2 dst = MessagePack.unpack(raw, OptionalBaseClass2.class); + assertTrue(src.f0 == dst.f0); + assertEquals(src.f1, dst.f1); + } finally { + TemplateRegistry.unregister(OptionalBaseClass2.class); + TemplateRegistry.unregister(OptionalMessagePackMessageClass2.class); + } + } + + @Test + public void testOptionalMessagePackMessageFieldClass02() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(OptionalBaseClass2.class); + TemplatePrecompiler.saveTemplateClass(OptionalMessagePackMessageClass2.class); + + OptionalBaseClass2 src = null; + + try { + byte[] raw = MessagePack.pack(src); + OptionalBaseClass2 dst = MessagePack.unpack(raw, OptionalBaseClass2.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(OptionalBaseClass2.class); + TemplateRegistry.unregister(OptionalMessagePackMessageClass2.class); + } + } + + @MessagePackMessage + public static class OptionalBaseClass2 { + @Optional + public int f0; + @Optional + public OptionalMessagePackMessageClass2 f1; + + public OptionalBaseClass2() { + } + } + + @MessagePackMessage + public static class OptionalMessagePackMessageClass2 { + @Optional + public int f2; + + public OptionalMessagePackMessageClass2() { + } + } + + @Test + public void testExtendedClass00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleSuperClass.class); + TemplatePrecompiler.saveTemplateClass(SampleSubClass.class); + + SampleSubClass src = new SampleSubClass(); + src.f0 = 0; + src.f2 = 2; + src.f3 = 3; + src.f4 = 4; + src.f5 = 5; + src.f8 = 8; + src.f9 = 9; + + try { + byte[] raw = MessagePack.pack(src); + SampleSubClass dst = MessagePack.unpack(raw, SampleSubClass.class); + assertTrue(src.f0 == dst.f0); + assertTrue(src.f1 == dst.f1); + assertTrue(src.f2 != dst.f2); + assertTrue(src.f3 != dst.f3); + assertTrue(src.f4 != dst.f4); + assertTrue(src.f5 == dst.f5); + assertTrue(src.f6 == dst.f6); + assertTrue(src.f8 != dst.f8); + assertTrue(src.f9 != dst.f9); + } finally { + TemplateRegistry.unregister(SampleSuperClass.class); + TemplateRegistry.unregister(SampleSubClass.class); + } + } + + @Test + public void testExtendedClass01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleSuperClass.class); + TemplatePrecompiler.saveTemplateClass(SampleSubClass.class); + + SampleSubClass src = null; + + try { + byte[] raw = MessagePack.pack(src); + SampleSubClass dst = MessagePack.unpack(raw, SampleSubClass.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(SampleSuperClass.class); + TemplateRegistry.unregister(SampleSubClass.class); + } + } + + @MessagePackMessage + public static class SampleSubClass extends SampleSuperClass { + public int f0; + public final int f1 = 1; + private int f2; + protected int f3; + int f4; + + public SampleSubClass() { + } + } + + @MessagePackMessage + public static class SampleSuperClass { + public int f5; + public final int f6 = 2; + @SuppressWarnings("unused") + private int f7; + protected int f8; + int f9; + + public SampleSuperClass() { + } + } + + @Test + public void testOptionalExtendedClass00() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleOptionalSuperClass.class); + TemplatePrecompiler.saveTemplateClass(SampleOptionalSubClass.class); + + SampleOptionalSubClass src = new SampleOptionalSubClass(); + src.f0 = 0; + src.f2 = 2; + src.f3 = 3; + src.f4 = 4; + src.f5 = 5; + src.f8 = 8; + src.f9 = 9; + + try { + byte[] raw = MessagePack.pack(src); + SampleOptionalSubClass dst = MessagePack.unpack(raw, SampleOptionalSubClass.class); + assertTrue(src.f0 == dst.f0); + assertTrue(src.f1 == dst.f1); + assertTrue(src.f2 != dst.f2); + assertTrue(src.f3 != dst.f3); + assertTrue(src.f4 != dst.f4); + assertTrue(src.f5 == dst.f5); + assertTrue(src.f6 == dst.f6); + assertTrue(src.f8 != dst.f8); + assertTrue(src.f9 != dst.f9); + } finally { + TemplateRegistry.unregister(SampleOptionalSuperClass.class); + TemplateRegistry.unregister(SampleOptionalSubClass.class); + } + } + + @Test + public void testOptionalExtendedClass01() throws Exception { + System.getProperties().setProperty(TemplatePrecompiler.DEST, "./target/test-classes"); + TemplatePrecompiler.saveTemplateClass(SampleOptionalSuperClass.class); + TemplatePrecompiler.saveTemplateClass(SampleOptionalSubClass.class); + + SampleOptionalSubClass src = null; + + try { + byte[] raw = MessagePack.pack(src); + SampleOptionalSubClass dst = MessagePack.unpack(raw, SampleOptionalSubClass.class); + assertEquals(src, dst); + } finally { + TemplateRegistry.unregister(SampleOptionalSuperClass.class); + TemplateRegistry.unregister(SampleOptionalSubClass.class); + } + } + + @MessagePackMessage + public static class SampleOptionalSubClass extends SampleOptionalSuperClass { + @Optional + public int f0; + public final int f1 = 1; + private int f2; + protected int f3; + int f4; + + public SampleOptionalSubClass() { + } + } + + @MessagePackMessage + public static class SampleOptionalSuperClass { + @Optional + public int f5; + public final int f6 = 2; + @SuppressWarnings("unused") + private int f7; + protected int f8; + int f9; + + public SampleOptionalSuperClass() { + } + } +}