diff --git a/.gitignore b/.gitignore
index d740b181..b39017b2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,8 @@
*.o
*.so
ruby/Makefile
+*.5
+*.8
+*.6
+_obj
+_test
diff --git a/cpp/ChangeLog b/cpp/ChangeLog
index 71c7d5bf..6d7f486d 100644
--- a/cpp/ChangeLog
+++ b/cpp/ChangeLog
@@ -1,4 +1,10 @@
+2011-02-24 version 0.5.5:
+
+ * eliminates dependency of winsock2.h header
+ * fixes msgpack_vc.postbuild.bat file
+ * fixes some implicit cast warnings
+
2010-08-29 version 0.5.4:
* includes msgpack_vc2008.vcproj file in source package
diff --git a/cpp/configure.in b/cpp/configure.in
index 23d7d6ee..f017b7cf 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.4)
+AM_INIT_AUTOMAKE(msgpack, 0.5.5)
AC_CONFIG_HEADER(config.h)
AC_SUBST(CFLAGS)
diff --git a/cpp/preprocess b/cpp/preprocess
index e51c61cf..17e8a05c 100755
--- a/cpp/preprocess
+++ b/cpp/preprocess
@@ -12,7 +12,7 @@ preprocess() {
fi
}
-if [ "$1" == "clean" ];then
+if [ "$1" = "clean" ];then
rm -f src/msgpack/type/tuple.hpp
rm -f src/msgpack/type/define.hpp
rm -f src/msgpack/zone.hpp
diff --git a/cpp/src/msgpack/pack.h b/cpp/src/msgpack/pack.h
index c1564963..f86e9299 100644
--- a/cpp/src/msgpack/pack.h
+++ b/cpp/src/msgpack/pack.h
@@ -105,9 +105,6 @@ int msgpack_pack_object(msgpack_packer* pk, msgpack_object d);
#define msgpack_pack_inline_func_cint(name) \
inline int msgpack_pack ## name
-#define msgpack_pack_inline_func_cint(name) \
- inline int msgpack_pack ## name
-
#define msgpack_pack_inline_func_fixint(name) \
inline int msgpack_pack_fix ## name
diff --git a/cpp/test/Makefile.am b/cpp/test/Makefile.am
index 5225f28b..5aeb8f19 100644
--- a/cpp/test/Makefile.am
+++ b/cpp/test/Makefile.am
@@ -1,7 +1,7 @@
AM_CPPFLAGS = -I../src
AM_C_CPPFLAGS = -I../src
-AM_LDFLAGS = ../src/libmsgpack.la -lgtest_main
+AM_LDFLAGS = ../src/libmsgpack.la -lgtest_main -pthread
check_PROGRAMS = \
zone \
diff --git a/go/Makefile b/go/Makefile
new file mode 100644
index 00000000..adc243af
--- /dev/null
+++ b/go/Makefile
@@ -0,0 +1,11 @@
+include $(GOROOT)/src/Make.inc
+
+TARG=msgpack
+
+GOFILES=pack.go unpack.go
+
+include $(GOROOT)/src/Make.pkg
+
+%: install %.go
+ $(GC) $*.go
+ $(LD) -o $@ $*.$O
diff --git a/go/msgpack_test.go b/go/msgpack_test.go
new file mode 100644
index 00000000..50de668a
--- /dev/null
+++ b/go/msgpack_test.go
@@ -0,0 +1,218 @@
+package msgpack_test
+
+import (
+ . "msgpack"
+ "testing"
+ "bytes"
+ "reflect"
+ "math"
+);
+
+func equal(lhs reflect.Value, rhs reflect.Value) bool {
+ {
+ _rhs, ok := rhs.(*reflect.InterfaceValue)
+ if ok { return equal(lhs, _rhs.Elem()) }
+ }
+ switch _lhs := lhs.(type) {
+ case *reflect.InterfaceValue:
+ return equal(_lhs.Elem(), rhs)
+ case *reflect.BoolValue:
+ _rhs, ok := rhs.(*reflect.BoolValue)
+ return ok && _lhs.Get() == _rhs.Get()
+ case *reflect.UintValue:
+ _rhs, ok := rhs.(*reflect.UintValue)
+ return ok && _lhs.Get() == _rhs.Get()
+ case *reflect.IntValue:
+ _rhs, ok := rhs.(*reflect.IntValue)
+ return ok && _lhs.Get() == _rhs.Get()
+ case *reflect.FloatValue:
+ _rhs, ok := rhs.(*reflect.FloatValue)
+ return ok && _lhs.Get() == _rhs.Get()
+ case reflect.ArrayOrSliceValue:
+ _rhs := rhs.(reflect.ArrayOrSliceValue)
+ if _lhs.Len() != _rhs.Len() { return false; }
+ for i := 0; i < _lhs.Len(); i++ {
+ if !equal(_lhs.Elem(i), _rhs.Elem(i)) { return false; }
+ }
+ return true;
+ case *reflect.MapValue:
+ _rhs := rhs.(*reflect.MapValue)
+ if _lhs.Len() != _rhs.Len() { return false; }
+ for _, k := range _lhs.Keys() {
+ lv, rv := _lhs.Elem(k), _rhs.Elem(k)
+ if lv == nil || rv == nil || !equal(lv, rv) { return false; }
+ }
+ return true;
+ }
+ return false;
+}
+
+func TestPackUint8(t *testing.T) {
+ b := &bytes.Buffer{}
+ for _, i := range []uint8 { 0, 1, 2, 125, 126, 127, 128, 253, 254, 255 } {
+ _, err := PackUint8(b, i)
+ if err != nil { t.Error("err != nil") }
+ }
+ if bytes.Compare(b.Bytes(), []byte { 0x00, 0x01, 0x02, 0x7d, 0x7e, 0x7f, 0xcc, 0x80, 0xcc, 0xfd, 0xcc, 0xfe, 0xcc, 0xff }) != 0 { t.Error("wrong output", b.Bytes()) }
+}
+
+func TestPackUint16(t *testing.T) {
+ b := &bytes.Buffer{}
+ for _, i := range []uint16 { 0, 1, 2, 125, 126, 127, 128, 253, 254, 255, 256, 65533, 65534, 65535 } {
+ _, err := PackUint16(b, i)
+ if err != nil { t.Error("err != nil") }
+ }
+ if bytes.Compare(b.Bytes(), []byte { 0x00, 0x01, 0x02, 0x7d, 0x7e, 0x7f, 0xcc, 0x80, 0xcc, 0xfd, 0xcc, 0xfe, 0xcc, 0xff, 0xcd, 0x01, 0x00, 0xcd, 0xff, 0xfd, 0xcd, 0xff, 0xfe, 0xcd, 0xff, 0xff }) != 0 { t.Error("wrong output", b.Bytes()) }
+}
+
+func TestPackUint32(t *testing.T) {
+ b := &bytes.Buffer{}
+ for _, i := range []uint32 { 0, 1, 2, 125, 126, 127, 128, 253, 254, 255, 256, 65533, 65534, 65535, 65536, 4294967293, 4294967294, 4294967295 } {
+ _, err := PackUint32(b, i)
+ if err != nil { t.Error("err != nil") }
+ }
+ if bytes.Compare(b.Bytes(), []byte { 0x00, 0x01, 0x02, 0x7d, 0x7e, 0x7f, 0xcc, 0x80, 0xcc, 0xfd, 0xcc, 0xfe, 0xcc, 0xff, 0xcd, 0x01, 0x00, 0xcd, 0xff, 0xfd, 0xcd, 0xff, 0xfe, 0xcd, 0xff, 0xff, 0xce, 0x00, 0x01, 0x00, 0x00, 0xce, 0xff, 0xff, 0xff, 0xfd, 0xce, 0xff, 0xff, 0xff, 0xfe, 0xce, 0xff, 0xff, 0xff, 0xff }) != 0 { t.Error("wrong output", b.Bytes()) }
+}
+
+func TestPackUint64(t *testing.T) {
+ b := &bytes.Buffer{}
+ for _, i := range []uint64 { 0, 1, 2, 125, 126, 127, 128, 253, 254, 255, 256, 65533, 65534, 65535, 65536, 4294967293, 4294967294, 4294967295, 4294967296, 18446744073709551613, 18446744073709551614, 18446744073709551615 } {
+ _, err := PackUint64(b, i)
+ if err != nil { t.Error("err != nil") }
+ }
+ if bytes.Compare(b.Bytes(), []byte { 0x00, 0x01, 0x02, 0x7d, 0x7e, 0x7f, 0xcc, 0x80, 0xcc, 0xfd, 0xcc, 0xfe, 0xcc, 0xff, 0xcd, 0x01, 0x00, 0xcd, 0xff, 0xfd, 0xcd, 0xff, 0xfe, 0xcd, 0xff, 0xff, 0xce, 0x00, 0x01, 0x00, 0x00, 0xce, 0xff, 0xff, 0xff, 0xfd, 0xce, 0xff, 0xff, 0xff, 0xfe, 0xce, 0xff, 0xff, 0xff, 0xff, 0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }) != 0 { t.Error("wrong output", b.Bytes()) }
+}
+
+func TestPackInt8(t *testing.T) {
+ b := &bytes.Buffer{}
+ for _, i := range []int8 { -128, -127, -34, -33, -32, -31, 0, 1, 126, 127 } {
+ _, err := PackInt8(b, i)
+ if err != nil { t.Error("err != nil") }
+ }
+ if bytes.Compare(b.Bytes(), []byte { 0xd0, 0x80, 0xd0, 0x81, 0xd0, 0xde, 0xd0, 0xdf, 0xe0, 0xe1, 0x00, 0x01, 0x7e, 0x7f }) != 0 { t.Error("wrong output", b.Bytes()) }
+}
+
+func TestPackInt16(t *testing.T) {
+ b := &bytes.Buffer{}
+ for _, i := range []int16 { -32768, -32767, -131, -130, -129, -128, -127, -34, -33, -32, -31, 0, 1, 126, 127, 128, 129, 130, 32765, 32766, 32767 } {
+ _, err := PackInt16(b, i)
+ if err != nil { t.Error("err != nil") }
+ }
+ if bytes.Compare(b.Bytes(), []byte { 0xd1, 0x80, 0x00, 0xd1, 0x80, 0x01, 0xd1, 0xff, 0x7d, 0xd1, 0xff, 0x7e, 0xd1, 0xff, 0x7f, 0xd0, 0x80, 0xd0, 0x81, 0xd0, 0xde, 0xd0, 0xdf, 0xe0, 0xe1, 0x00, 0x01, 0x7e, 0x7f, 0xd1, 0x00, 0x80, 0xd1, 0x00, 0x81, 0xd1, 0x00, 0x82, 0xd1, 0x7f, 0xfd, 0xd1, 0x7f, 0xfe, 0xd1, 0x7f, 0xff }) != 0 { t.Error("wrong output", b.Bytes()) }
+}
+
+func TestPackInt32(t *testing.T) {
+ b := &bytes.Buffer{}
+ for _, i := range []int32 { -2147483648, -2147483647, -2147483646, -32771, -32770, -32769, -32768, -32767, -131, -130, -129, -128, -127, -34, -33, -32, -31, 0, 1, 126, 127, 128, 129, 130, 32765, 32766, 32767, 32768, 32769, 32770, 2147483645, 2147483646, 2147483647 } {
+ _, err := PackInt32(b, i)
+ if err != nil { t.Error("err != nil") }
+ }
+ if bytes.Compare(b.Bytes(), []byte { 0xd2, 0x80, 0x00, 0x00, 0x00, 0xd2, 0x80, 0x00, 0x00, 0x01, 0xd2, 0x80, 0x00, 0x00, 0x02, 0xd2, 0xff, 0xff, 0x7f, 0xfd, 0xd2, 0xff, 0xff, 0x7f, 0xfe, 0xd2, 0xff, 0xff, 0x7f, 0xff, 0xd1, 0x80, 0x00, 0xd1, 0x80, 0x01, 0xd1, 0xff, 0x7d, 0xd1, 0xff, 0x7e, 0xd1, 0xff, 0x7f, 0xd0, 0x80, 0xd0, 0x81, 0xd0, 0xde, 0xd0, 0xdf, 0xe0, 0xe1, 0x00, 0x01, 0x7e, 0x7f, 0xd1, 0x00, 0x80, 0xd1, 0x00, 0x81, 0xd1, 0x00, 0x82, 0xd1, 0x7f, 0xfd, 0xd1, 0x7f, 0xfe, 0xd1, 0x7f, 0xff, 0xd2, 0x00, 0x00, 0x80, 0x00, 0xd2, 0x00, 0x00, 0x80, 0x01, 0xd2, 0x00, 0x00, 0x80, 0x02, 0xd2, 0x7f, 0xff, 0xff, 0xfd, 0xd2, 0x7f, 0xff, 0xff, 0xfe, 0xd2, 0x7f, 0xff, 0xff, 0xff }) != 0 { t.Error("wrong output", b.Bytes()) }
+}
+
+func TestPackInt64(t *testing.T) {
+ b := &bytes.Buffer{}
+ for _, i := range []int64 { -9223372036854775808, -9223372036854775807, -9223372036854775806, -2147483651, -2147483650, -2147483649, -2147483648, -2147483647, -2147483646, -32771, -32770, -32769, -32768, -32767, -131, -130, -129, -128, -127, -34, -33, -32, -31, 0, 1, 126, 127, 128, 129, 130, 32765, 32766, 32767, 32768, 32769, 32770, 2147483645, 2147483646, 2147483647, 2147483648, 2147483649, 2147483650, 4294967296, 4294967297, 4294967298 } {
+ _, err := PackInt64(b, i)
+ if err != nil { t.Error("err != nil") }
+ }
+ if bytes.Compare(b.Bytes(), []byte { 0xd3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xd3, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xfd, 0xd3, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xfe, 0xd3, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xd2, 0x80, 0x00, 0x00, 0x00, 0xd2, 0x80, 0x00, 0x00, 0x01, 0xd2, 0x80, 0x00, 0x00, 0x02, 0xd2, 0xff, 0xff, 0x7f, 0xfd, 0xd2, 0xff, 0xff, 0x7f, 0xfe, 0xd2, 0xff, 0xff, 0x7f, 0xff, 0xd1, 0x80, 0x00, 0xd1, 0x80, 0x01, 0xd1, 0xff, 0x7d, 0xd1, 0xff, 0x7e, 0xd1, 0xff, 0x7f, 0xd0, 0x80, 0xd0, 0x81, 0xd0, 0xde, 0xd0, 0xdf, 0xe0, 0xe1, 0x00, 0x01, 0x7e, 0x7f, 0xd1, 0x00, 0x80, 0xd1, 0x00, 0x81, 0xd1, 0x00, 0x82, 0xd1, 0x7f, 0xfd, 0xd1, 0x7f, 0xfe, 0xd1, 0x7f, 0xff, 0xd2, 0x00, 0x00, 0x80, 0x00, 0xd2, 0x00, 0x00, 0x80, 0x01, 0xd2, 0x00, 0x00, 0x80, 0x02, 0xd2, 0x7f, 0xff, 0xff, 0xfd, 0xd2, 0x7f, 0xff, 0xff, 0xfe, 0xd2, 0x7f, 0xff, 0xff, 0xff, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x02, 0xd3, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0xd3, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02 }) != 0 { t.Error("wrong output", b.Bytes()) }
+}
+
+func TestPackNil(t *testing.T) {
+ b := &bytes.Buffer{}
+ nbyteswrite, err := PackNil(b)
+ if nbyteswrite != 1 { t.Error("nbyteswrite != 1") }
+ if err != nil { t.Error("err != nil") }
+ if bytes.Compare(b.Bytes(), []byte { 0xc0 }) != 0 { t.Error("wrong output", b.Bytes()) }
+}
+
+func TestPackBool(t *testing.T) {
+ b := &bytes.Buffer{}
+ for _, i := range []bool { false, true } {
+ nbyteswrite, err := PackBool(b, i)
+ if nbyteswrite != 1 { t.Error("nbyteswrite != 1") }
+ if err != nil { t.Error("err != nil") }
+ }
+ if bytes.Compare(b.Bytes(), []byte { 0xc2, 0xc3 }) != 0 { t.Error("wrong output", b.Bytes()) }
+}
+
+func TestPackInt32Array(t *testing.T) {
+ b := &bytes.Buffer{}
+ _, err := PackInt32Array(b, []int32 {})
+ if err != nil { t.Error("err != nil") }
+ _, err = PackInt32Array(b, []int32 { 0 })
+ if err != nil { t.Error("err != nil") }
+ _, err = PackInt32Array(b, []int32 { 0, 1 })
+ if err != nil { t.Error("err != nil") }
+ _, err = PackInt32Array(b, []int32 { 0, 1, 2 })
+ if err != nil { t.Error("err != nil") }
+ if bytes.Compare(b.Bytes(), []byte { 0x90, 0x91, 0x00, 0x92, 0x00, 0x01, 0x93, 0x00, 0x01, 0x02 }) != 0 { t.Error("wrong output", b.Bytes()) }
+}
+
+func TestPackArray(t *testing.T) {
+ b := &bytes.Buffer{}
+ _, err := PackArray(b, reflect.NewValue([]int32 {}).(reflect.ArrayOrSliceValue))
+ if err != nil { t.Error("err != nil") }
+ _, err = PackArray(b, reflect.NewValue([]int32 { 0 }).(reflect.ArrayOrSliceValue))
+ if err != nil { t.Error("err != nil") }
+ _, err = PackArray(b, reflect.NewValue([]int32 { 0, 1 }).(reflect.ArrayOrSliceValue))
+ if err != nil { t.Error("err != nil") }
+ _, err = PackArray(b, reflect.NewValue([]int32 { 0, 1, 2 }).(reflect.ArrayOrSliceValue))
+ if err != nil { t.Error("err != nil") }
+ if bytes.Compare(b.Bytes(), []byte { 0x90, 0x91, 0x00, 0x92, 0x00, 0x01, 0x93, 0x00, 0x01, 0x02 }) != 0 { t.Error("wrong output", b.Bytes()) }
+}
+
+func TestPackMap(t *testing.T) {
+ b := &bytes.Buffer{}
+ _, err := PackMap(b, reflect.NewValue(map[int] int { 0: 1, 2: 3, 4: 5 }).(*reflect.MapValue))
+ if err != nil { t.Error("err != nil") }
+ if bytes.Compare(b.Bytes(), []byte { 0x83, 0x00, 0x01, 0x04, 0x05, 0x02, 0x03 }) != 0 { t.Error("wrong output", b.Bytes()) }
+}
+
+func TestPack(t *testing.T) {
+ b := &bytes.Buffer{}
+ for _, i := range [](interface{}) { nil, false, true, 0, 1, 2, 3, 127, -32, -1, -33, 128 } {
+ _, err := Pack(b, i)
+ if err != nil { t.Error("err != nil") }
+ }
+ if bytes.Compare(b.Bytes(), []byte { 0xc0, 0xc2, 0xc3, 0x00, 0x01, 0x02, 0x03, 0x7f, 0xf0, 0xff, 0xd0, 0xef, 0xd1, 0x00, 0x80 }) == 0 { t.Error("wrong output") }
+}
+
+func TestUnpackArray(t *testing.T) {
+ b := bytes.NewBuffer([]byte { 0x90, 0x91, 0x00, 0x92, 0x00, 0x01, 0x93, 0xd1, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x01, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xdc, 0x00, 0x02, 0x00, 0x01, 0xdd, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02, 0x03 })
+ for _, v := range [](interface{}) { [](interface{}) {}, [](interface{}) { int8(0) }, [](interface{}) { int8(0), int8(1) }, [](interface{}) { int16(0), int32(1), int64(2) }, [](interface{}){ int8(0), int8(1) }, [](interface{}) { int8(0), int8(1), int8(2), int8(3) } } {
+ retval, _, e := Unpack(b)
+ if e != nil { t.Error("err != nil") }
+ if !equal(reflect.NewValue(retval.Interface()), reflect.NewValue(v)) { t.Errorf("%s != %s", retval.Interface(), v) }
+ }
+}
+
+func TestUnpackInt(t *testing.T) {
+ b := bytes.NewBuffer([]byte { 0xff, 0xe0, 0x00, 0x01, 0x02, 0x7d, 0x7e, 0x7f, 0xd0, 0x01, 0xd0, 0x80, 0xd0, 0xff, 0xcc, 0x80, 0xcc, 0xfd, 0xcc, 0xfe, 0xcc, 0xff, 0xd1, 0x00, 0x00, 0xd1, 0x7f, 0xff, 0xd1, 0xff, 0xff, 0xcd, 0x80, 0x00, 0xcd, 0xff, 0xff, 0xd2, 0x7f, 0xff, 0xff, 0xff, 0xce, 0x7f, 0xff, 0xff, 0xff, 0xd3, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff })
+ for _, v := range [](interface{}) {
+ int8(-1), int8(-32), int8(0), int8(1), int8(2), int8(125), int8(126), int8(127), int8(1), int8(-128), int8(-1), uint8(128), uint8(253), uint8(254), uint8(255), int16(0), int16(32767), int16(-1), uint16(32768), uint16(65535), int32(2147483647), uint32(2147483647), int64(9223372036854775807), uint64(18446744073709551615) } {
+ retval, _, e := Unpack(b)
+ if e != nil { t.Error("err != nil") }
+ if retval.Interface() != v { t.Errorf("%u != %u", retval.Interface(), v) }
+ }
+}
+
+func TestUnpackFloat(t *testing.T) {
+ b := bytes.NewBuffer([]byte { 0xca, 0x3d, 0xcc, 0xcc, 0xcd, 0xca, 0x3e, 0x4c, 0xcc, 0xcd, 0xca, 0xbd, 0xcc, 0xcc, 0xcd, 0xca, 0xbe, 0x4c, 0xcc, 0xcd, 0xca, 0x7f, 0x80, 0x00, 0x00, 0xca, 0xff, 0x80, 0x00, 0x00, 0xca, 0xff, 0xc0, 0x00, 0x0, 0xcb, 0x3f, 0xb9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xcb, 0x3f, 0xc9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xcb, 0xbf, 0xb9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xcb, 0xbf, 0xc9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xcb, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcb, 0xcb, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcb, 0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 })
+ for _, v := range [](interface{}) { float32(.1), float32(.2), float32(-.1), float32(-.2), float32(math.Inf(1)), float32(math.Inf(-1)), float32(math.NaN()), float64(.1), float64(.2), float64(-.1), float64(-.2) } {
+ retval, _, e := Unpack(b)
+ if e != nil { t.Error("err != nil") }
+ isnan := false
+ if _v, ok := v.(float64); ok {
+ isnan = math.IsNaN(_v)
+ } else if _v, ok := v.(float32); ok {
+ isnan = math.IsNaN(float64(_v))
+ }
+ if isnan {
+ if retval.Interface() == v { t.Errorf("[NaN] %u == %u", retval.Interface(), v) }
+ } else {
+ if retval.Interface() != v { t.Errorf("%u != %u", retval.Interface(), v) }
+ }
+ }
+}
diff --git a/go/pack.go b/go/pack.go
new file mode 100644
index 00000000..c129166e
--- /dev/null
+++ b/go/pack.go
@@ -0,0 +1,591 @@
+package msgpack
+
+import (
+ "io"
+ "os"
+ "unsafe"
+ "reflect"
+);
+
+// Packs a given value and writes it into the specified writer.
+func PackUint8(writer io.Writer, value uint8) (n int, err os.Error) {
+ if value < 128 {
+ return writer.Write([]byte { byte(value) })
+ }
+ return writer.Write([]byte { 0xcc, byte(value) })
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackUint16(writer io.Writer, value uint16) (n int, err os.Error) {
+ if value < 128 {
+ return writer.Write([]byte { byte(value) })
+ } else if value < 256 {
+ return writer.Write([]byte { 0xcc, byte(value) })
+ }
+ return writer.Write([]byte { 0xcd, byte(value >> 8), byte(value) })
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackUint32(writer io.Writer, value uint32) (n int, err os.Error) {
+ if value < 128 {
+ return writer.Write([]byte { byte(value) })
+ } else if value < 256 {
+ return writer.Write([]byte { 0xcc, byte(value) })
+ } else if value < 65536 {
+ return writer.Write([]byte { 0xcd, byte(value >> 8), byte(value) })
+ }
+ return writer.Write([]byte { 0xce, byte(value >> 24), byte(value >> 16), byte(value >> 8), byte(value) })
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackUint64(writer io.Writer, value uint64) (n int, err os.Error) {
+ if value < 128 {
+ return writer.Write([]byte { byte(value) })
+ } else if value < 256 {
+ return writer.Write([]byte { 0xcc, byte(value) })
+ } else if value < 65536 {
+ return writer.Write([]byte { 0xcd, byte(value >> 8), byte(value) })
+ } else if value < 4294967296 {
+ return writer.Write([]byte { 0xce, byte(value >> 24), byte(value >> 16), byte(value >> 8), byte(value) })
+ }
+ return writer.Write([]byte { 0xcf, byte(value >> 56), byte(value >> 48), byte(value >> 40), byte(value >> 32), byte(value >> 24), byte(value >> 16), byte(value >> 8), byte(value) })
+}
+
+func PackUint(writer io.Writer, value uint) (n int, err os.Error) {
+// Packs a given value and writes it into the specified writer.
+ switch unsafe.Sizeof(value) {
+ case 4:
+ return PackUint32(writer, *(*uint32)(unsafe.Pointer(&value)))
+ case 8:
+ return PackUint64(writer, *(*uint64)(unsafe.Pointer(&value)))
+ }
+ return 0, os.ENOENT // never get here
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackInt8(writer io.Writer, value int8) (n int, err os.Error) {
+ if value < -32 {
+ return writer.Write([]byte { 0xd0, byte(value) })
+ }
+ return writer.Write([]byte { byte(value) })
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackInt16(writer io.Writer, value int16) (n int, err os.Error) {
+ if value < -128 || value >= 128 {
+ return writer.Write([]byte { 0xd1, byte(uint16(value) >> 8), byte(value) })
+ } else if value < -32 {
+ return writer.Write([]byte { 0xd0, byte(value) })
+ }
+ return writer.Write([]byte { byte(value) })
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackInt32(writer io.Writer, value int32) (n int, err os.Error) {
+ if value < -32768 || value >= 32768 {
+ return writer.Write([]byte { 0xd2, byte(uint32(value) >> 24), byte(uint32(value) >> 16), byte(uint32(value) >> 8), byte(value) })
+ } else if value < -128 {
+ return writer.Write([]byte { 0xd1, byte(uint32(value) >> 8), byte(value) })
+ } else if value < -32 {
+ return writer.Write([]byte { 0xd0, byte(value) })
+ } else if value >= 128 {
+ return writer.Write([]byte { 0xd1, byte(uint32(value) >> 8), byte(value) })
+ }
+ return writer.Write([]byte { byte(value) })
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackInt64(writer io.Writer, value int64) (n int, err os.Error) {
+ if value < -2147483648 || value >= 2147483648 {
+ return writer.Write([]byte { 0xd3, byte(uint64(value) >> 56), byte(uint64(value) >> 48), byte(uint64(value) >> 40), byte(uint64(value) >> 32), byte(uint64(value) >> 24), byte(uint64(value) >> 16), byte(uint64(value) >> 8), byte(value) })
+ } else if value < -32768 || value >= 32768 {
+ return writer.Write([]byte { 0xd2, byte(uint64(value) >> 24), byte(uint64(value) >> 16), byte(uint64(value) >> 8), byte(value) })
+ } else if value < -128 || value >= 128 {
+ return writer.Write([]byte { 0xd1, byte(uint64(value) >> 8), byte(value) })
+ } else if value < -32 {
+ return writer.Write([]byte { 0xd0, byte(value) })
+ }
+ return writer.Write([]byte { byte(value) })
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackInt(writer io.Writer, value int) (n int, err os.Error) {
+ switch unsafe.Sizeof(value) {
+ case 4:
+ return PackInt32(writer, *(*int32)(unsafe.Pointer(&value)))
+ case 8:
+ return PackInt64(writer, *(*int64)(unsafe.Pointer(&value)))
+ }
+ return 0, os.ENOENT // never get here
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackNil(writer io.Writer) (n int, err os.Error) {
+ return writer.Write([]byte{ 0xc0 })
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackBool(writer io.Writer, value bool) (n int, err os.Error) {
+ var code byte;
+ if value {
+ code = 0xc3
+ } else {
+ code = 0xc2
+ }
+ return writer.Write([]byte{ code })
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackFloat32(writer io.Writer, value float32) (n int, err os.Error) {
+ return PackUint32(writer, *(*uint32)(unsafe.Pointer(&value)))
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackFloat64(writer io.Writer, value float64) (n int, err os.Error) {
+ return PackUint64(writer, *(*uint64)(unsafe.Pointer(&value)))
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackBytes(writer io.Writer, value []byte) (n int, err os.Error) {
+ if len(value) < 32 {
+ n1, err := writer.Write([]byte { 0xa0 | uint8(len(value)) })
+ if err != nil { return n1, err }
+ n2, err := writer.Write(value)
+ return n1 + n2, err
+ } else if len(value) < 65536 {
+ n1, err := writer.Write([]byte { 0xda, byte(len(value) >> 16), byte(len(value)) })
+ if err != nil { return n1, err }
+ n2, err := writer.Write(value)
+ return n1 + n2, err
+ }
+ n1, err := writer.Write([]byte { 0xdb, byte(len(value) >> 24), byte(len(value) >> 16), byte(len(value) >> 8), byte(len(value)) })
+ if err != nil { return n1, err }
+ n2, err := writer.Write(value)
+ return n1 + n2, err
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackUint16Array(writer io.Writer, value []uint16) (n int, err os.Error) {
+ if len(value) < 16 {
+ n, err := writer.Write([]byte { 0x90 | byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackUint16(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else if len(value) < 65536 {
+ n, err := writer.Write([]byte { 0xdc, byte(len(value) >> 8), byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackUint16(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else {
+ n, err := writer.Write([]byte { 0xdd, byte(len(value) >> 24), byte(len(value) >> 16), byte(len(value) >> 8), byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackUint16(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ }
+ return n, nil
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackUint32Array(writer io.Writer, value []uint32) (n int, err os.Error) {
+ if len(value) < 16 {
+ n, err := writer.Write([]byte { 0x90 | byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackUint32(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else if len(value) < 65536 {
+ n, err := writer.Write([]byte { 0xdc, byte(len(value) >> 8), byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackUint32(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else {
+ n, err := writer.Write([]byte { 0xdd, byte(len(value) >> 24), byte(len(value) >> 16), byte(len(value) >> 8), byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackUint32(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ }
+ return n, nil
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackUint64Array(writer io.Writer, value []uint64) (n int, err os.Error) {
+ if len(value) < 16 {
+ n, err := writer.Write([]byte { 0x90 | byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackUint64(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else if len(value) < 65536 {
+ n, err := writer.Write([]byte { 0xdc, byte(len(value) >> 8), byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackUint64(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else {
+ n, err := writer.Write([]byte { 0xdd, byte(len(value) >> 24), byte(len(value) >> 16), byte(len(value) >> 8), byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackUint64(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ }
+ return n, nil
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackUintArray(writer io.Writer, value []uint) (n int, err os.Error) {
+ switch unsafe.Sizeof(0) {
+ case 4:
+ return PackUint32Array(writer, *(*[]uint32)(unsafe.Pointer(&value)))
+ case 8:
+ return PackUint64Array(writer, *(*[]uint64)(unsafe.Pointer(&value)))
+ }
+ return 0, os.ENOENT // never get here
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackInt8Array(writer io.Writer, value []int8) (n int, err os.Error) {
+ if len(value) < 16 {
+ n, err := writer.Write([]byte { 0x90 | byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackInt8(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else if len(value) < 65536 {
+ n, err := writer.Write([]byte { 0xdc, byte(len(value) >> 8), byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackInt8(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else {
+ n, err := writer.Write([]byte { 0xdd, byte(len(value) >> 24), byte(len(value) >> 16), byte(len(value) >> 8), byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackInt8(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ }
+ return n, nil
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackInt16Array(writer io.Writer, value []int16) (n int, err os.Error) {
+ if len(value) < 16 {
+ n, err := writer.Write([]byte { 0x90 | byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackInt16(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else if len(value) < 65536 {
+ n, err := writer.Write([]byte { 0xdc, byte(len(value) >> 8), byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackInt16(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else {
+ n, err := writer.Write([]byte { 0xdd, byte(len(value) >> 24), byte(len(value) >> 16), byte(len(value) >> 8), byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackInt16(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ }
+ return n, nil
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackInt32Array(writer io.Writer, value []int32) (n int, err os.Error) {
+ if len(value) < 16 {
+ n, err := writer.Write([]byte { 0x90 | byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackInt32(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else if len(value) < 65536 {
+ n, err := writer.Write([]byte { 0xdc, byte(len(value) >> 8), byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackInt32(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else {
+ n, err := writer.Write([]byte { 0xdd, byte(len(value) >> 24), byte(len(value) >> 16), byte(len(value) >> 8), byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackInt32(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ }
+ return n, nil
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackInt64Array(writer io.Writer, value []int64) (n int, err os.Error) {
+ if len(value) < 16 {
+ n, err := writer.Write([]byte { 0x90 | byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackInt64(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else if len(value) < 65536 {
+ n, err := writer.Write([]byte { 0xdc, byte(len(value) >> 8), byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackInt64(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else {
+ n, err := writer.Write([]byte { 0xdd, byte(len(value) >> 24), byte(len(value) >> 16), byte(len(value) >> 8), byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackInt64(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ }
+ return n, nil
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackIntArray(writer io.Writer, value []int) (n int, err os.Error) {
+ switch unsafe.Sizeof(0) {
+ case 4:
+ return PackInt32Array(writer, *(*[]int32)(unsafe.Pointer(&value)))
+ case 8:
+ return PackInt64Array(writer, *(*[]int64)(unsafe.Pointer(&value)))
+ }
+ return 0, os.ENOENT // never get here
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackFloat32Array(writer io.Writer, value []float32) (n int, err os.Error) {
+ if len(value) < 16 {
+ n, err := writer.Write([]byte { 0x90 | byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackFloat32(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else if len(value) < 65536 {
+ n, err := writer.Write([]byte { 0xdc, byte(len(value) >> 8), byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackFloat32(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else {
+ n, err := writer.Write([]byte { 0xdd, byte(len(value) >> 24), byte(len(value) >> 16), byte(len(value) >> 8), byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackFloat32(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ }
+ return n, nil
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackFloat64Array(writer io.Writer, value []float64) (n int, err os.Error) {
+ if len(value) < 16 {
+ n, err := writer.Write([]byte { 0x90 | byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackFloat64(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else if len(value) < 65536 {
+ n, err := writer.Write([]byte { 0xdc, byte(len(value) >> 8), byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackFloat64(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else {
+ n, err := writer.Write([]byte { 0xdd, byte(len(value) >> 24), byte(len(value) >> 16), byte(len(value) >> 8), byte(len(value)) })
+ if err != nil { return n, err }
+ for _, i := range value {
+ _n, err := PackFloat64(writer, i)
+ if err != nil { return n, err }
+ n += _n
+ }
+ }
+ return n, nil
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackArray(writer io.Writer, value reflect.ArrayOrSliceValue) (n int, err os.Error) {
+ {
+ elemType, ok := value.Type().(reflect.ArrayOrSliceType).Elem().(*reflect.UintType)
+ if ok && elemType.Kind() == reflect.Uint8 {
+ return PackBytes(writer, value.Interface().([]byte))
+ }
+ }
+
+ l := value.Len()
+ if l < 16 {
+ n, err := writer.Write([]byte { 0x90 | byte(l) })
+ if err != nil { return n, err }
+ for i := 0; i < l; i++ {
+ _n, err := PackValue(writer, value.Elem(i))
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else if l < 65536 {
+ n, err := writer.Write([]byte { 0xdc, byte(l >> 8), byte(l) })
+ if err != nil { return n, err }
+ for i := 0; i < l; i++ {
+ _n, err := PackValue(writer, value.Elem(i))
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else {
+ n, err := writer.Write([]byte { 0xdd, byte(l >> 24), byte(l >> 16), byte(l >> 8), byte(l) })
+ if err != nil { return n, err }
+ for i := 0; i < l; i++ {
+ _n, err := PackValue(writer, value.Elem(i))
+ if err != nil { return n, err }
+ n += _n
+ }
+ }
+ return n, nil
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackMap(writer io.Writer, value *reflect.MapValue) (n int, err os.Error) {
+ keys := value.Keys()
+ if value.Len() < 16 {
+ n, err := writer.Write([]byte { 0x80 | byte(len(keys)) })
+ if err != nil { return n, err }
+ for _, k := range keys {
+ _n, err := PackValue(writer, k)
+ if err != nil { return n, err }
+ n += _n
+ _n, err = PackValue(writer, value.Elem(k))
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else if value.Len() < 65536 {
+ n, err := writer.Write([]byte { 0xde, byte(len(keys) >> 8), byte(len(keys)) })
+ if err != nil { return n, err }
+ for _, k := range keys {
+ _n, err := PackValue(writer, k)
+ if err != nil { return n, err }
+ n += _n
+ _n, err = PackValue(writer, value.Elem(k))
+ if err != nil { return n, err }
+ n += _n
+ }
+ } else {
+ n, err := writer.Write([]byte { 0xdf, byte(len(keys) >> 24), byte(len(keys) >> 16), byte(len(keys) >> 8), byte(len(keys)) })
+ if err != nil { return n, err }
+ for _, k := range keys {
+ _n, err := PackValue(writer, k)
+ if err != nil { return n, err }
+ n += _n
+ _n, err = PackValue(writer, value.Elem(k))
+ if err != nil { return n, err }
+ n += _n
+ }
+ }
+ return n, nil
+}
+
+// Packs a given value and writes it into the specified writer.
+func PackValue(writer io.Writer, value reflect.Value) (n int, err os.Error) {
+ if value == nil || value.Type() == nil { return PackNil(writer) }
+ switch _value := value.(type) {
+ case *reflect.BoolValue: return PackBool(writer, _value.Get())
+ case *reflect.UintValue: return PackUint64(writer, _value.Get())
+ case *reflect.IntValue: return PackInt64(writer, _value.Get())
+ case *reflect.FloatValue: return PackFloat64(writer, _value.Get())
+ case *reflect.ArrayValue: return PackArray(writer, _value)
+ case *reflect.SliceValue: return PackArray(writer, _value)
+ case *reflect.MapValue: return PackMap(writer, _value)
+ case *reflect.InterfaceValue:
+ __value := reflect.NewValue(_value.Interface())
+ _, ok := __value.(*reflect.InterfaceValue)
+ if !ok {
+ return PackValue(writer, __value)
+ }
+ }
+ panic("unsupported type: " + value.Type().String())
+}
+
+// Packs a given value and writes it into the specified writer.
+func Pack(writer io.Writer, value interface{}) (n int, err os.Error) {
+ if value == nil { return PackNil(writer) }
+ switch _value := value.(type) {
+ case bool: return PackBool(writer, _value)
+ case uint8: return PackUint8(writer, _value)
+ case uint16: return PackUint16(writer, _value)
+ case uint32: return PackUint32(writer, _value)
+ case uint64: return PackUint64(writer, _value)
+ case uint: return PackUint(writer, _value)
+ case int8: return PackInt8(writer, _value)
+ case int16: return PackInt16(writer, _value)
+ case int32: return PackInt32(writer, _value)
+ case int64: return PackInt64(writer, _value)
+ case int: return PackInt(writer, _value)
+ case float32: return PackFloat32(writer, _value)
+ case float64: return PackFloat64(writer, _value)
+ case []byte: return PackBytes(writer, _value)
+ case []uint16: return PackUint16Array(writer, _value)
+ case []uint32: return PackUint32Array(writer, _value)
+ case []uint64: return PackUint64Array(writer, _value)
+ case []uint: return PackUintArray(writer, _value)
+ case []int8: return PackInt8Array(writer, _value)
+ case []int16: return PackInt16Array(writer, _value)
+ case []int32: return PackInt32Array(writer, _value)
+ case []int64: return PackInt64Array(writer, _value)
+ case []int: return PackIntArray(writer, _value)
+ case []float32: return PackFloat32Array(writer, _value)
+ case []float64: return PackFloat64Array(writer, _value)
+ default:
+ return PackValue(writer, reflect.NewValue(value))
+ }
+ return 0, nil // never get here
+}
diff --git a/go/unpack.go b/go/unpack.go
new file mode 100644
index 00000000..6bf0159d
--- /dev/null
+++ b/go/unpack.go
@@ -0,0 +1,288 @@
+package msgpack
+
+import (
+ "io"
+ "os"
+ "unsafe"
+ "strconv"
+ "reflect"
+)
+
+func readByte(reader io.Reader) (v uint8, err os.Error) {
+ data := [1]byte{}
+ _, e := reader.Read(data[0:])
+ if e != nil { return 0, e }
+ return data[0], nil
+}
+
+func readUint16(reader io.Reader) (v uint16, n int, err os.Error) {
+ data := [2]byte{}
+ n, e := reader.Read(data[0:])
+ if e != nil { return 0, n, e }
+ return (uint16(data[0]) << 8) | uint16(data[1]), n, nil
+}
+
+func readUint32(reader io.Reader) (v uint32, n int, err os.Error) {
+ data := [4]byte{}
+ n, e := reader.Read(data[0:])
+ if e != nil { return 0, n, e }
+ return (uint32(data[0]) << 24) | (uint32(data[1]) << 16) | (uint32(data[2]) << 8) | uint32(data[3]), n, nil
+}
+
+func readUint64(reader io.Reader) (v uint64, n int, err os.Error) {
+ data := [8]byte{}
+ n, e := reader.Read(data[0:])
+ if e != nil { return 0, n, e }
+ return (uint64(data[0]) << 56) | (uint64(data[1]) << 48) | (uint64(data[2]) << 40) | (uint64(data[3]) << 32) | (uint64(data[4]) << 24) | (uint64(data[5]) << 16) | (uint64(data[6]) << 8) | uint64(data[7]), n, nil
+}
+
+func readInt16(reader io.Reader) (v int16, n int, err os.Error) {
+ data := [2]byte{}
+ n, e := reader.Read(data[0:])
+ if e != nil { return 0, n, e }
+ return (int16(data[0]) << 8) | int16(data[1]), n, nil
+}
+
+func readInt32(reader io.Reader) (v int32, n int, err os.Error) {
+ data := [4]byte{}
+ n, e := reader.Read(data[0:])
+ if e != nil { return 0, n, e }
+ return (int32(data[0]) << 24) | (int32(data[1]) << 16) | (int32(data[2]) << 8) | int32(data[3]), n, nil
+}
+
+func readInt64(reader io.Reader) (v int64, n int, err os.Error) {
+ data := [8]byte{}
+ n, e := reader.Read(data[0:])
+ if e != nil { return 0, n, e }
+ return (int64(data[0]) << 56) | (int64(data[1]) << 48) | (int64(data[2]) << 40) | (int64(data[3]) << 32) | (int64(data[4]) << 24) | (int64(data[5]) << 16) | (int64(data[6]) << 8) | int64(data[7]), n, nil
+}
+
+func unpackArray(reader io.Reader, nelems uint) (v reflect.Value, n int, err os.Error) {
+ retval := make([]interface{}, nelems)
+ nbytesread := 0
+ var i uint
+ for i = 0; i < nelems; i++ {
+ v, n, e := Unpack(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ retval[i] = v.Interface()
+ }
+ return reflect.NewValue(retval), nbytesread, nil
+}
+
+func unpackArrayReflected(reader io.Reader, nelems uint) (v reflect.Value, n int, err os.Error) {
+ retval := make([]reflect.Value, nelems)
+ nbytesread := 0
+ var i uint
+ for i = 0; i < nelems; i++ {
+ v, n, e := UnpackReflected(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ retval[i] = v
+ }
+ return reflect.NewValue(retval), nbytesread, nil
+}
+
+func unpackMap(reader io.Reader, nelems uint) (v reflect.Value, n int, err os.Error) {
+ retval := make(map [interface{}] interface{})
+ nbytesread := 0
+ var i uint
+ for i = 0; i < nelems; i++ {
+ k, n, e := Unpack(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ v, n, e := Unpack(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ retval[k.Interface()] = v.Interface()
+ }
+ return reflect.NewValue(retval), nbytesread, nil
+}
+
+func unpackMapReflected(reader io.Reader, nelems uint) (v reflect.Value, n int, err os.Error) {
+ retval := make(map [reflect.Value] reflect.Value)
+ nbytesread := 0
+ var i uint
+ for i = 0; i < nelems; i++ {
+ k, n, e := UnpackReflected(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ v, n, e := UnpackReflected(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ retval[k] = v
+ }
+ return reflect.NewValue(retval), nbytesread, nil
+}
+
+func unpack(reader io.Reader, reflected bool) (v reflect.Value, n int, err os.Error) {
+ var retval reflect.Value
+ var nbytesread int = 0
+
+ c, e := readByte(reader)
+ if e != nil { return nil, 0, e }
+ nbytesread += 1
+ if c < 0x80 || c >= 0xe0 {
+ retval = reflect.NewValue(int8(c))
+ } else if c >= 0x80 && c <= 0x8f {
+ if reflected {
+ retval, n, e = unpackMapReflected(reader, uint(c & 0xf))
+ } else {
+ retval, n, e = unpackMap(reader, uint(c & 0xf))
+ }
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ nbytesread += n
+ } else if c >= 0x90 && c <= 0x9f {
+ if reflected {
+ retval, n, e = unpackArrayReflected(reader, uint(c & 0xf))
+ } else {
+ retval, n, e = unpackArray(reader, uint(c & 0xf))
+ }
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ nbytesread += n
+ } else if c >= 0xa0 && c <= 0xbf {
+ data := make([]byte, c & 0xf);
+ n, e := reader.Read(data)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ retval = reflect.NewValue(data)
+ } else {
+ switch c {
+ case 0xc0: retval = reflect.NewValue(nil)
+ case 0xc2: retval = reflect.NewValue(false)
+ case 0xc3: retval = reflect.NewValue(true)
+ case 0xca:
+ data, n, e := readUint32(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ retval = reflect.NewValue(*(*float32)(unsafe.Pointer(&data)))
+ case 0xcb:
+ data, n, e := readUint64(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ retval = reflect.NewValue(*(*float64)(unsafe.Pointer(&data)))
+ case 0xcc:
+ data, e := readByte(reader)
+ if e != nil { return nil, nbytesread, e }
+ retval = reflect.NewValue(uint8(data))
+ nbytesread += 1
+ case 0xcd:
+ data, n, e := readUint16(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ retval = reflect.NewValue(data)
+ case 0xce:
+ data, n, e := readUint32(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ retval = reflect.NewValue(data)
+ case 0xcf:
+ data, n, e := readUint64(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ retval = reflect.NewValue(data)
+ case 0xd0:
+ data, e := readByte(reader)
+ if e != nil { return nil, nbytesread, e }
+ retval = reflect.NewValue(int8(data))
+ nbytesread += 1
+ case 0xd1:
+ data, n, e := readInt16(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ retval = reflect.NewValue(data)
+ case 0xd2:
+ data, n, e := readInt32(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ retval = reflect.NewValue(data)
+ case 0xd3:
+ data, n, e := readInt64(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ retval = reflect.NewValue(data)
+ case 0xda:
+ nbytestoread, n, e := readUint16(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ data := make([]byte, nbytestoread)
+ n, e = reader.Read(data)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ retval = reflect.NewValue(data)
+ case 0xdb:
+ nbytestoread, n, e := readUint32(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ data := make([]byte, nbytestoread)
+ n, e = reader.Read(data)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ retval = reflect.NewValue(data)
+ case 0xdc:
+ nelemstoread, n, e := readUint16(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ if reflected {
+ retval, n, e = unpackArrayReflected(reader, uint(nelemstoread))
+ } else {
+ retval, n, e = unpackArray(reader, uint(nelemstoread))
+ }
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ case 0xdd:
+ nelemstoread, n, e := readUint32(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ if reflected {
+ retval, n, e = unpackArrayReflected(reader, uint(nelemstoread))
+ } else {
+ retval, n, e = unpackArray(reader, uint(nelemstoread))
+ }
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ case 0xde:
+ nelemstoread, n, e := readUint16(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ if reflected {
+ retval, n, e = unpackMapReflected(reader, uint(nelemstoread))
+ } else {
+ retval, n, e = unpackMap(reader, uint(nelemstoread))
+ }
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ case 0xdf:
+ nelemstoread, n, e := readUint32(reader)
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ if reflected {
+ retval, n, e = unpackMapReflected(reader, uint(nelemstoread))
+ } else {
+ retval, n, e = unpackMap(reader, uint(nelemstoread))
+ }
+ nbytesread += n
+ if e != nil { return nil, nbytesread, e }
+ default:
+ panic("unsupported code: " + strconv.Itoa(int(c)))
+ }
+ }
+ return retval, nbytesread, nil
+}
+
+// Reads a value from the reader, unpack and returns it.
+func Unpack(reader io.Reader) (v reflect.Value, n int, err os.Error) {
+ return unpack(reader, false)
+}
+
+// Reads unpack a value from the reader, unpack and returns it. When the
+// value is an array or map, leaves the elements wrapped by corresponding
+// wrapper objects defined in reflect package.
+func UnpackReflected(reader io.Reader) (v reflect.Value, n int, err os.Error) {
+ return unpack(reader, true)
+}
+
+
+
diff --git a/haskell/msgpack.cabal b/haskell/msgpack.cabal
index 98133a9e..02f1ec16 100644
--- a/haskell/msgpack.cabal
+++ b/haskell/msgpack.cabal
@@ -1,12 +1,12 @@
Name: msgpack
-Version: 0.4.0.1
-Synopsis: A Haskell binding to MessagePack
+Version: 0.6.1.1
+Synopsis: A Haskell implementation of MessagePack
Description:
- A Haskell binding to MessagePack
+ A Haskell implementation of MessagePack
License: BSD3
License-File: LICENSE
-Copyright: Copyright (c) 2009-2010, Hideyuki Tanaka
+Copyright: Copyright (c) 2009-2011, Hideyuki Tanaka
Category: Data
Author: Hideyuki Tanaka
Maintainer: Hideyuki Tanaka
@@ -21,28 +21,30 @@ Extra-source-files:
Library
Build-depends: base >=4 && <5,
- transformers >= 0.2.1 && < 0.2.2,
- MonadCatchIO-transformers >= 0.2.2 && < 0.2.3,
+ transformers >= 0.2 && < 0.3,
bytestring >= 0.9 && < 0.10,
- vector >= 0.6.0 && < 0.6.1,
- iteratee >= 0.4 && < 0.5,
- attoparsec >= 0.8.1 && < 0.8.2,
+ text >= 0.11 && < 0.12,
+ vector >= 0.7 && < 0.8,
+ attoparsec >= 0.8 && < 0.9,
binary >= 0.5.0 && < 0.5.1,
data-binary-ieee754 >= 0.4 && < 0.5,
deepseq >= 1.1 && <1.2,
- template-haskell >= 2.4 && < 2.5
+ template-haskell >= 2.4 && < 2.6
Ghc-options: -Wall
Hs-source-dirs: src
Exposed-modules:
Data.MessagePack
+ Data.MessagePack.Assoc
Data.MessagePack.Pack
Data.MessagePack.Unpack
Data.MessagePack.Object
- Data.MessagePack.Iteratee
Data.MessagePack.Derive
+ Other-modules:
+ Data.MessagePack.Internal.Utf8
+
Source-repository head
Type: git
Location: git://github.com/msgpack/msgpack.git
diff --git a/haskell/src/Data/MessagePack.hs b/haskell/src/Data/MessagePack.hs
index b71190d6..801c2738 100644
--- a/haskell/src/Data/MessagePack.hs
+++ b/haskell/src/Data/MessagePack.hs
@@ -13,91 +13,15 @@
--------------------------------------------------------------------
module Data.MessagePack(
+ module Data.MessagePack.Assoc,
module Data.MessagePack.Pack,
module Data.MessagePack.Unpack,
module Data.MessagePack.Object,
- module Data.MessagePack.Iteratee,
module Data.MessagePack.Derive,
-
- -- * Pack functions
- packToString,
- packToHandle,
- packToHandle',
- packToFile,
-
- -- * Unpack functions
- unpackFromString,
- unpackFromHandle,
- unpackFromFile,
- unpackFromStringI,
- unpackFromHandleI,
- unpackFromFileI,
-
) where
-import qualified Control.Monad.CatchIO as CIO
-import Control.Monad.IO.Class
-import qualified Data.Attoparsec as A
-import Data.Binary.Put
-import qualified Data.ByteString as B
-import qualified Data.ByteString.Lazy as L
-import qualified Data.Iteratee as I
-import System.IO
-
+import Data.MessagePack.Assoc
import Data.MessagePack.Pack
import Data.MessagePack.Unpack
import Data.MessagePack.Object
-import Data.MessagePack.Iteratee
import Data.MessagePack.Derive
-
-bufferSize :: Int
-bufferSize = 4 * 1024
-
--- | Pack to ByteString.
-packToString :: Put -> L.ByteString
-packToString = runPut
-
--- | Pack to Handle
-packToHandle :: Handle -> Put -> IO ()
-packToHandle h = L.hPutStr h . packToString
-
--- | Pack to Handle and Flush Handle
-packToHandle' :: Handle -> Put -> IO ()
-packToHandle' h p = packToHandle h p >> hFlush h
-
--- | Pack to File
-packToFile :: FilePath -> Put -> IO ()
-packToFile path = L.writeFile path . packToString
-
--- | Unpack from ByteString
-unpackFromString :: (Monad m, IsByteString s) => s -> A.Parser a -> m a
-unpackFromString bs =
- unpackFromStringI bs . parserToIteratee
-
--- | Unpack from Handle
-unpackFromHandle :: CIO.MonadCatchIO m => Handle -> A.Parser a -> m a
-unpackFromHandle h =
- unpackFromHandleI h .parserToIteratee
-
--- | Unpack from File
-unpackFromFile :: CIO.MonadCatchIO m => FilePath -> A.Parser a -> m a
-unpackFromFile path =
- unpackFromFileI path . parserToIteratee
-
--- | Iteratee interface to unpack from ByteString
-unpackFromStringI :: (Monad m, IsByteString s) => s -> I.Iteratee B.ByteString m a -> m a
-unpackFromStringI bs =
- I.run . I.joinIM . I.enumPure1Chunk (toBS bs)
-
--- | Iteratee interface to unpack from Handle
-unpackFromHandleI :: CIO.MonadCatchIO m => Handle -> I.Iteratee B.ByteString m a -> m a
-unpackFromHandleI h =
- I.run . I.joinIM . enumHandleNonBlocking bufferSize h
-
--- | Iteratee interface to unpack from File
-unpackFromFileI :: CIO.MonadCatchIO m => FilePath -> I.Iteratee B.ByteString m a -> m a
-unpackFromFileI path p =
- CIO.bracket
- (liftIO $ openBinaryFile path ReadMode)
- (liftIO . hClose)
- (flip unpackFromHandleI p)
diff --git a/haskell/src/Data/MessagePack/Assoc.hs b/haskell/src/Data/MessagePack/Assoc.hs
new file mode 100644
index 00000000..525cb77f
--- /dev/null
+++ b/haskell/src/Data/MessagePack/Assoc.hs
@@ -0,0 +1,28 @@
+{-# Language DeriveDataTypeable #-}
+{-# Language GeneralizedNewtypeDeriving #-}
+
+--------------------------------------------------------------------
+-- |
+-- Module : Data.MessagePack.Assoc
+-- Copyright : (c) Daiki Handa, 2010
+-- License : BSD3
+--
+-- Maintainer: tanaka.hideyuki@gmail.com
+-- Stability : experimental
+-- Portability: portable
+--
+-- MessagePack map labeling type
+--
+--------------------------------------------------------------------
+
+module Data.MessagePack.Assoc (
+ Assoc(..)
+ ) where
+
+import Control.DeepSeq
+import Data.Typeable
+
+-- not defined for general Functor for performance reason.
+-- (ie. you would want to write custom instances for each type using specialized mapM-like functions)
+newtype Assoc a=Assoc{unAssoc :: a} deriving(Show,Eq,Ord,Typeable,NFData)
+
diff --git a/haskell/src/Data/MessagePack/Internal/Utf8.hs b/haskell/src/Data/MessagePack/Internal/Utf8.hs
new file mode 100644
index 00000000..c109faaa
--- /dev/null
+++ b/haskell/src/Data/MessagePack/Internal/Utf8.hs
@@ -0,0 +1,28 @@
+module Data.MessagePack.Internal.Utf8 (
+ encodeUtf8,
+ decodeUtf8,
+ skipChar,
+ toLBS,
+ fromLBS,
+ ) where
+
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as BL
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
+import qualified Data.Text.Encoding.Error as T
+
+encodeUtf8 :: String -> B.ByteString
+encodeUtf8 = T.encodeUtf8 . T.pack
+
+decodeUtf8 :: B.ByteString -> String
+decodeUtf8 = T.unpack . T.decodeUtf8With skipChar
+
+skipChar :: T.OnDecodeError
+skipChar _ _ = Nothing
+
+toLBS :: B.ByteString -> BL.ByteString
+toLBS bs = BL.fromChunks [bs]
+
+fromLBS :: BL.ByteString -> B.ByteString
+fromLBS = B.concat . BL.toChunks
diff --git a/haskell/src/Data/MessagePack/Iteratee.hs b/haskell/src/Data/MessagePack/Iteratee.hs
deleted file mode 100644
index 6bc08980..00000000
--- a/haskell/src/Data/MessagePack/Iteratee.hs
+++ /dev/null
@@ -1,82 +0,0 @@
---------------------------------------------------------------------
--- |
--- Module : Data.MessagePack.Iteratee
--- Copyright : (c) Hideyuki Tanaka, 2009-2010
--- License : BSD3
---
--- Maintainer: tanaka.hideyuki@gmail.com
--- Stability : experimental
--- Portability: portable
---
--- MessagePack Deserializer interface to @Data.Iteratee@
---
---------------------------------------------------------------------
-
-module Data.MessagePack.Iteratee(
- -- * Iteratee version of deserializer
- getI,
- -- * Non Blocking Enumerator
- enumHandleNonBlocking,
- -- * Convert Parser to Iteratee
- parserToIteratee,
- ) where
-
-import Control.Exception
-import Control.Monad.IO.Class
-import qualified Data.Attoparsec as A
-import qualified Data.ByteString as B
-import qualified Data.Iteratee as I
-import System.IO
-
-import Data.MessagePack.Unpack
-
--- | Deserialize a value
-getI :: (Monad m, Unpackable a) => I.Iteratee B.ByteString m a
-getI = parserToIteratee get
-
--- | Enumerator
-enumHandleNonBlocking :: MonadIO m => Int -> Handle -> I.Enumerator B.ByteString m a
-enumHandleNonBlocking bufSize h =
- I.enumFromCallback $ readSome bufSize h
-
-readSome :: MonadIO m => Int -> Handle -> m (Either SomeException (Bool, B.ByteString))
-readSome bufSize h = liftIO $ do
- ebs <- try $ hGetSome bufSize h
- case ebs of
- Left exc ->
- return $ Left (exc :: SomeException)
- Right bs | B.null bs ->
- return $ Right (False, B.empty)
- Right bs ->
- return $ Right (True, bs)
-
-hGetSome :: Int -> Handle -> IO B.ByteString
-hGetSome bufSize h = do
- bs <- B.hGetNonBlocking h bufSize
- if B.null bs
- then do
- hd <- B.hGet h 1
- if B.null hd
- then do
- return B.empty
- else do
- rest <- B.hGetNonBlocking h (bufSize - 1)
- return $ B.cons (B.head hd) rest
- else do
- return bs
-
--- | Convert Parser to Iteratee
-parserToIteratee :: Monad m => A.Parser a -> I.Iteratee B.ByteString m a
-parserToIteratee p = I.icont (itr (A.parse p)) Nothing
- where
- itr pcont s = case s of
- I.EOF _ ->
- I.throwErr (I.setEOF s)
- I.Chunk bs ->
- case pcont bs of
- A.Fail _ _ msg ->
- I.throwErr (I.iterStrExc msg)
- A.Partial cont ->
- I.icont (itr cont) Nothing
- A.Done remain ret ->
- I.idone ret (I.Chunk remain)
diff --git a/haskell/src/Data/MessagePack/Object.hs b/haskell/src/Data/MessagePack/Object.hs
index 5111ebb6..aaad669c 100644
--- a/haskell/src/Data/MessagePack/Object.hs
+++ b/haskell/src/Data/MessagePack/Object.hs
@@ -1,6 +1,5 @@
{-# Language TypeSynonymInstances #-}
{-# Language FlexibleInstances #-}
-{-# Language OverlappingInstances #-}
{-# Language IncoherentInstances #-}
{-# Language DeriveDataTypeable #-}
@@ -33,22 +32,30 @@ import Control.Monad
import Control.Monad.Trans.Error ()
import qualified Data.Attoparsec as A
import qualified Data.ByteString as B
-import qualified Data.ByteString.Char8 as C8
+import qualified Data.ByteString.Lazy as BL
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
+import qualified Data.Text.Lazy as TL
+import qualified Data.Text.Lazy.Encoding as TL
import Data.Typeable
+import Data.MessagePack.Assoc
import Data.MessagePack.Pack
import Data.MessagePack.Unpack
+import Data.MessagePack.Internal.Utf8
-- | Object Representation of MessagePack data.
-data Object =
- ObjectNil
+data Object
+ = ObjectNil
| ObjectBool Bool
| ObjectInteger Int
+ | ObjectFloat Float
| ObjectDouble Double
| ObjectRAW B.ByteString
| ObjectArray [Object]
| ObjectMap [(Object, Object)]
deriving (Show, Eq, Ord, Typeable)
+
instance NFData Object where
rnf obj =
@@ -56,21 +63,24 @@ instance NFData Object where
ObjectNil -> ()
ObjectBool b -> rnf b
ObjectInteger n -> rnf n
+ ObjectFloat f -> rnf f
ObjectDouble d -> rnf d
ObjectRAW bs -> bs `seq` ()
ObjectArray a -> rnf a
ObjectMap m -> rnf m
+
instance Unpackable Object where
get =
A.choice
[ liftM ObjectInteger get
, liftM (\() -> ObjectNil) get
, liftM ObjectBool get
+ , liftM ObjectFloat get
, liftM ObjectDouble get
, liftM ObjectRAW get
, liftM ObjectArray get
- , liftM ObjectMap get
+ , liftM (ObjectMap . unAssoc) get
]
instance Packable Object where
@@ -82,6 +92,8 @@ instance Packable Object where
put ()
ObjectBool b ->
put b
+ ObjectFloat f ->
+ put f
ObjectDouble d ->
put d
ObjectRAW raw ->
@@ -89,7 +101,7 @@ instance Packable Object where
ObjectArray arr ->
put arr
ObjectMap m ->
- put m
+ put $ Assoc m
-- | The class of types serializable to and from MessagePack object
class (Unpackable a, Packable a) => OBJECT a where
@@ -137,14 +149,34 @@ instance OBJECT Double where
tryFromObject (ObjectDouble d) = Right d
tryFromObject _ = tryFromObjectError
+instance OBJECT Float where
+ toObject = ObjectFloat
+ tryFromObject (ObjectFloat f) = Right f
+ tryFromObject _ = tryFromObjectError
+
+instance OBJECT String where
+ toObject = toObject . encodeUtf8
+ tryFromObject obj = liftM decodeUtf8 $ tryFromObject obj
+
instance OBJECT B.ByteString where
toObject = ObjectRAW
tryFromObject (ObjectRAW bs) = Right bs
tryFromObject _ = tryFromObjectError
-instance OBJECT String where
- toObject = toObject . C8.pack
- tryFromObject obj = liftM C8.unpack $ tryFromObject obj
+instance OBJECT BL.ByteString where
+ toObject = ObjectRAW . fromLBS
+ tryFromObject (ObjectRAW bs) = Right $ toLBS bs
+ tryFromObject _ = tryFromObjectError
+
+instance OBJECT T.Text where
+ toObject = ObjectRAW . T.encodeUtf8
+ tryFromObject (ObjectRAW bs) = Right $ T.decodeUtf8With skipChar bs
+ tryFromObject _ = tryFromObjectError
+
+instance OBJECT TL.Text where
+ toObject = ObjectRAW . fromLBS . TL.encodeUtf8
+ tryFromObject (ObjectRAW bs) = Right $ TL.decodeUtf8With skipChar $ toLBS bs
+ tryFromObject _ = tryFromObjectError
instance OBJECT a => OBJECT [a] where
toObject = ObjectArray . map toObject
@@ -285,11 +317,11 @@ instance (OBJECT a1, OBJECT a2, OBJECT a3, OBJECT a4, OBJECT a5, OBJECT a6, OBJE
tryFromObject _ =
tryFromObjectError
-instance (OBJECT a, OBJECT b) => OBJECT [(a, b)] where
+instance (OBJECT a, OBJECT b) => OBJECT (Assoc [(a,b)]) where
toObject =
- ObjectMap . map (\(a, b) -> (toObject a, toObject b))
+ ObjectMap . map (\(a, b) -> (toObject a, toObject b)) . unAssoc
tryFromObject (ObjectMap mem) = do
- mapM (\(a, b) -> liftM2 (,) (tryFromObject a) (tryFromObject b)) mem
+ liftM Assoc $ mapM (\(a, b) -> liftM2 (,) (tryFromObject a) (tryFromObject b)) mem
tryFromObject _ =
tryFromObjectError
@@ -299,3 +331,4 @@ instance OBJECT a => OBJECT (Maybe a) where
tryFromObject ObjectNil = return Nothing
tryFromObject obj = liftM Just $ tryFromObject obj
+
diff --git a/haskell/src/Data/MessagePack/Pack.hs b/haskell/src/Data/MessagePack/Pack.hs
index 16243ad9..39394ff6 100644
--- a/haskell/src/Data/MessagePack/Pack.hs
+++ b/haskell/src/Data/MessagePack/Pack.hs
@@ -1,6 +1,5 @@
{-# Language FlexibleInstances #-}
{-# Language IncoherentInstances #-}
-{-# Language OverlappingInstances #-}
{-# Language TypeSynonymInstances #-}
--------------------------------------------------------------------
@@ -28,17 +27,23 @@ import Data.Binary.Put
import Data.Binary.IEEE754
import Data.Bits
import qualified Data.ByteString as B
-import qualified Data.ByteString.Char8 as B8
-import qualified Data.ByteString.Lazy as L
+import qualified Data.ByteString.Lazy as BL
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
+import qualified Data.Text.Lazy as TL
+import qualified Data.Text.Lazy.Encoding as TL
import qualified Data.Vector as V
+import Data.MessagePack.Assoc
+import Data.MessagePack.Internal.Utf8
+
-- | Serializable class
class Packable a where
-- | Serialize a value
put :: a -> Put
-- | Pack Haskell data to MessagePack string.
-pack :: Packable a => a -> L.ByteString
+pack :: Packable a => a -> BL.ByteString
pack = runPut . put
instance Packable Int where
@@ -81,23 +86,35 @@ instance Packable Bool where
put True = putWord8 0xC3
put False = putWord8 0xC2
+instance Packable Float where
+ put f = do
+ putWord8 0xCA
+ putFloat32be f
+
instance Packable Double where
put d = do
putWord8 0xCB
putFloat64be d
instance Packable String where
- put = putString length (putByteString . B8.pack)
+ put = putString encodeUtf8 B.length putByteString
instance Packable B.ByteString where
- put = putString B.length putByteString
+ put = putString id B.length putByteString
-instance Packable L.ByteString where
- put = putString (fromIntegral . L.length) putLazyByteString
+instance Packable BL.ByteString where
+ put = putString id (fromIntegral . BL.length) putLazyByteString
-putString :: (s -> Int) -> (s -> Put) -> s -> Put
-putString lf pf str = do
- case lf str of
+instance Packable T.Text where
+ put = putString T.encodeUtf8 B.length putByteString
+
+instance Packable TL.Text where
+ put = putString TL.encodeUtf8 (fromIntegral . BL.length) putLazyByteString
+
+putString :: (s -> t) -> (t -> Int) -> (t -> Put) -> s -> Put
+putString cnv lf pf str = do
+ let bs = cnv str
+ case lf bs of
len | len <= 31 -> do
putWord8 $ 0xA0 .|. fromIntegral len
len | len < 0x10000 -> do
@@ -106,7 +123,7 @@ putString lf pf str = do
len -> do
putWord8 0xDB
putWord32be $ fromIntegral len
- pf str
+ pf bs
instance Packable a => Packable [a] where
put = putArray length (mapM_ put)
@@ -159,11 +176,11 @@ putArray lf pf arr = do
putWord32be $ fromIntegral len
pf arr
-instance (Packable k, Packable v) => Packable [(k, v)] where
- put = putMap length (mapM_ putPair)
+instance (Packable k, Packable v) => Packable (Assoc [(k,v)]) where
+ put = putMap length (mapM_ putPair) . unAssoc
-instance (Packable k, Packable v) => Packable (V.Vector (k, v)) where
- put = putMap V.length (V.mapM_ putPair)
+instance (Packable k, Packable v) => Packable (Assoc (V.Vector (k,v))) where
+ put = putMap V.length (V.mapM_ putPair) . unAssoc
putPair :: (Packable a, Packable b) => (a, b) -> Put
putPair (a, b) = put a >> put b
@@ -184,3 +201,4 @@ putMap lf pf m = do
instance Packable a => Packable (Maybe a) where
put Nothing = put ()
put (Just a) = put a
+
diff --git a/haskell/src/Data/MessagePack/Unpack.hs b/haskell/src/Data/MessagePack/Unpack.hs
index a0d618ec..66a61a22 100644
--- a/haskell/src/Data/MessagePack/Unpack.hs
+++ b/haskell/src/Data/MessagePack/Unpack.hs
@@ -1,6 +1,5 @@
{-# Language FlexibleInstances #-}
{-# Language IncoherentInstances #-}
-{-# Language OverlappingInstances #-}
{-# Language TypeSynonymInstances #-}
{-# Language DeriveDataTypeable #-}
@@ -37,14 +36,20 @@ import Data.Binary.Get
import Data.Binary.IEEE754
import Data.Bits
import qualified Data.ByteString as B
-import qualified Data.ByteString.Char8 as B8
-import qualified Data.ByteString.Lazy as L
+import qualified Data.ByteString.Lazy as BL
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
+import qualified Data.Text.Lazy as TL
+import qualified Data.Text.Lazy.Encoding as TL
import Data.Int
import Data.Typeable
import qualified Data.Vector as V
import Data.Word
import Text.Printf
+import Data.MessagePack.Assoc
+import Data.MessagePack.Internal.Utf8
+
-- | Deserializable class
class Unpackable a where
-- | Deserialize a value
@@ -56,8 +61,8 @@ class IsByteString s where
instance IsByteString B.ByteString where
toBS = id
-instance IsByteString L.ByteString where
- toBS = B.concat . L.toChunks
+instance IsByteString BL.ByteString where
+ toBS = B.concat . BL.toChunks
-- | The exception of unpack
data UnpackError =
@@ -133,25 +138,38 @@ instance Unpackable Bool where
_ ->
fail $ printf "invlid bool tag: 0x%02X" c
-instance Unpackable Double where
+instance Unpackable Float where
get = do
c <- A.anyWord8
case c of
0xCA ->
- return . realToFrac . runGet getFloat32be . toLBS =<< A.take 4
+ return . runGet getFloat32be . toLBS =<< A.take 4
+ _ ->
+ fail $ printf "invlid float tag: 0x%02X" c
+
+instance Unpackable Double where
+ get = do
+ c <- A.anyWord8
+ case c of
0xCB ->
return . runGet getFloat64be . toLBS =<< A.take 8
_ ->
fail $ printf "invlid double tag: 0x%02X" c
instance Unpackable String where
- get = parseString (\n -> return . B8.unpack =<< A.take n)
+ get = parseString (\n -> return . decodeUtf8 =<< A.take n)
instance Unpackable B.ByteString where
get = parseString A.take
-instance Unpackable L.ByteString where
- get = parseString (\n -> do bs <- A.take n; return $ L.fromChunks [bs])
+instance Unpackable BL.ByteString where
+ get = parseString (\n -> return . toLBS =<< A.take n)
+
+instance Unpackable T.Text where
+ get = parseString (\n -> return . T.decodeUtf8With skipChar =<< A.take n)
+
+instance Unpackable TL.Text where
+ get = parseString (\n -> return . TL.decodeUtf8With skipChar . toLBS =<< A.take n)
parseString :: (Int -> A.Parser a) -> A.Parser a
parseString aget = do
@@ -225,11 +243,11 @@ parseArray aget = do
_ ->
fail $ printf "invlid array tag: 0x%02X" c
-instance (Unpackable k, Unpackable v) => Unpackable [(k, v)] where
- get = parseMap (flip replicateM parsePair)
+instance (Unpackable k, Unpackable v) => Unpackable (Assoc [(k,v)]) where
+ get = liftM Assoc $ parseMap (flip replicateM parsePair)
-instance (Unpackable k, Unpackable v) => Unpackable (V.Vector (k, v)) where
- get = parseMap (flip V.replicateM parsePair)
+instance (Unpackable k, Unpackable v) => Unpackable (Assoc (V.Vector (k, v))) where
+ get = liftM Assoc $ parseMap (flip V.replicateM parsePair)
parsePair :: (Unpackable k, Unpackable v) => A.Parser (k, v)
parsePair = do
@@ -303,6 +321,3 @@ parseInt32 = return . fromIntegral =<< parseUint32
parseInt64 :: A.Parser Int64
parseInt64 = return . fromIntegral =<< parseUint64
-
-toLBS :: B.ByteString -> L.ByteString
-toLBS bs = L.fromChunks [bs]
diff --git a/haskell/test/Test.hs b/haskell/test/Test.hs
index 43af2efc..d3089634 100644
--- a/haskell/test/Test.hs
+++ b/haskell/test/Test.hs
@@ -7,6 +7,9 @@ import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy.Char8 as L
import Data.MessagePack
+instance Arbitrary a => Arbitrary (Assoc a) where
+ arbitrary = liftM Assoc arbitrary
+
mid :: (Packable a, Unpackable a) => a -> a
mid = unpack . pack
@@ -36,10 +39,12 @@ prop_mid_pair4 a = a == mid a
where types = a :: (Int, Int, Int, Int)
prop_mid_pair5 a = a == mid a
where types = a :: (Int, Int, Int, Int, Int)
-prop_mid_map_int_double a = a == mid a
+prop_mid_list_int_double a = a == mid a
where types = a :: [(Int, Double)]
-prop_mid_map_string_string a = a == mid a
+prop_mid_list_string_string a = a == mid a
where types = a :: [(String, String)]
+prop_mid_map_string_int a = a == mid a
+ where types = a :: Assoc [(String,Int)]
tests =
[ testGroup "simple"
@@ -56,8 +61,9 @@ tests =
, testProperty "(int, int, int)" prop_mid_pair3
, testProperty "(int, int, int, int)" prop_mid_pair4
, testProperty "(int, int, int, int, int)" prop_mid_pair5
- , testProperty "[(int, double)]" prop_mid_map_int_double
- , testProperty "[(string, string)]" prop_mid_map_string_string
+ , testProperty "[(int, double)]" prop_mid_list_int_double
+ , testProperty "[(string, string)]" prop_mid_list_string_string
+ , testProperty "Assoc [(string, int)]" prop_mid_map_string_int
]
]
diff --git a/java/.settings/org.eclipse.jdt.core.prefs b/java/.settings/org.eclipse.jdt.core.prefs
index c75ad473..c2f9169f 100755
--- a/java/.settings/org.eclipse.jdt.core.prefs
+++ b/java/.settings/org.eclipse.jdt.core.prefs
@@ -1,5 +1,6 @@
-#Mon Apr 19 22:18:48 JST 2010
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.source=1.6
-org.eclipse.jdt.core.compiler.compliance=1.6
+#Mon Sep 27 07:43:48 JST 2010
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/java/.settings/org.maven.ide.eclipse.prefs b/java/.settings/org.maven.ide.eclipse.prefs
new file mode 100644
index 00000000..6d8de378
--- /dev/null
+++ b/java/.settings/org.maven.ide.eclipse.prefs
@@ -0,0 +1,9 @@
+#Mon Sep 27 07:43:27 JST 2010
+activeProfiles=
+eclipse.preferences.version=1
+fullBuildGoals=process-test-resources
+includeModules=false
+resolveWorkspaceProjects=true
+resourceFilterGoals=process-resources resources\:testResources
+skipCompilerPlugin=true
+version=1
diff --git a/java/msgpack.iml b/java/msgpack.iml
new file mode 100644
index 00000000..3a6d962d
--- /dev/null
+++ b/java/msgpack.iml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java/pom.xml b/java/pom.xml
index c8a19b3a..b9abaa41 100755
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -63,8 +63,8 @@
maven-compiler-plugin
- 1.6
- 1.6
+ 1.5
+ 1.5
@@ -81,6 +81,20 @@
scm:git://github.com/msgpack/msgpack.git
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
@@ -132,12 +146,14 @@
msgpack.org
Repository at msgpack.org
file://${project.build.directory}/website/maven2/
+
true
msgpack.org
Repository at msgpack.org
file://${project.build.directory}/website/maven2/
+
diff --git a/java/src/main/java/org/msgpack/AbstractTemplate.java b/java/src/main/java/org/msgpack/AbstractTemplate.java
index 7f8cb49f..429a4705 100644
--- a/java/src/main/java/org/msgpack/AbstractTemplate.java
+++ b/java/src/main/java/org/msgpack/AbstractTemplate.java
@@ -1,7 +1,7 @@
//
// MessagePack for Java
//
-// Copyright (C) 2009-2010 FURUHASHI Sadayuki
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -23,5 +23,4 @@ public abstract class AbstractTemplate implements Template {
public Object unpack(Unpacker pac, Object to) throws IOException, MessageTypeException {
return convert(pac.unpackObject(), to);
}
-}
-
+}
\ No newline at end of file
diff --git a/java/src/main/java/org/msgpack/BufferedUnpackerImpl.java b/java/src/main/java/org/msgpack/BufferedUnpackerImpl.java
index 406fff73..30637a1a 100644
--- a/java/src/main/java/org/msgpack/BufferedUnpackerImpl.java
+++ b/java/src/main/java/org/msgpack/BufferedUnpackerImpl.java
@@ -146,10 +146,10 @@ abstract class BufferedUnpackerImpl extends UnpackerImpl {
advance(3);
return (int)castBuffer.getShort(0);
case 0xd2: // signed int 32
- more(4);
+ more(5);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 4);
- advance(4);
+ advance(5);
return (int)castBuffer.getInt(0);
case 0xd3: // signed int 64
more(9);
@@ -215,10 +215,10 @@ abstract class BufferedUnpackerImpl extends UnpackerImpl {
advance(3);
return (long)castBuffer.getShort(0);
case 0xd2: // signed int 32
- more(4);
+ more(5);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 4);
- advance(4);
+ advance(5);
return (long)castBuffer.getInt(0);
case 0xd3: // signed int 64
more(9);
diff --git a/java/src/main/java/org/msgpack/MessagePack.java b/java/src/main/java/org/msgpack/MessagePack.java
index f3a73c06..27cfc506 100644
--- a/java/src/main/java/org/msgpack/MessagePack.java
+++ b/java/src/main/java/org/msgpack/MessagePack.java
@@ -1,7 +1,7 @@
//
// MessagePack for Java
//
-// Copyright (C) 2009-2010 FURUHASHI Sadayuki
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -22,7 +22,6 @@ import java.io.InputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.msgpack.template.TemplateRegistry;
-import org.msgpack.template.TemplateBuilder;
import org.msgpack.template.FieldList;
public class MessagePack {
diff --git a/java/src/main/java/org/msgpack/MessagePackTemplateProvider.java b/java/src/main/java/org/msgpack/MessagePackTemplateProvider.java
index 511625b7..8f7515b6 100644
--- a/java/src/main/java/org/msgpack/MessagePackTemplateProvider.java
+++ b/java/src/main/java/org/msgpack/MessagePackTemplateProvider.java
@@ -1,7 +1,7 @@
//
// MessagePack for Java
//
-// Copyright (C) 2009-2010 FURUHASHI Sadayuki
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -18,6 +18,5 @@
package org.msgpack;
public interface MessagePackTemplateProvider {
-
Template getTemplate();
}
diff --git a/java/src/main/java/org/msgpack/Template.java b/java/src/main/java/org/msgpack/Template.java
index 19808afb..8cce999f 100644
--- a/java/src/main/java/org/msgpack/Template.java
+++ b/java/src/main/java/org/msgpack/Template.java
@@ -1,7 +1,7 @@
//
// MessagePack for Java
//
-// Copyright (C) 2009-2010 FURUHASHI Sadayuki
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -18,5 +18,4 @@
package org.msgpack;
public interface Template extends MessagePacker, MessageUnpacker, MessageConverter {
-}
-
+}
\ No newline at end of file
diff --git a/java/src/main/java/org/msgpack/Templates.java b/java/src/main/java/org/msgpack/Templates.java
index 4972670e..f268fa0b 100644
--- a/java/src/main/java/org/msgpack/Templates.java
+++ b/java/src/main/java/org/msgpack/Templates.java
@@ -1,7 +1,7 @@
//
// MessagePack for Java
//
-// Copyright (C) 2009-2010 FURUHASHI Sadayuki
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -76,6 +76,11 @@ public class Templates {
return TBigInteger;
}
+ public static final Template TBigDecimal = BigDecimalTemplate.getInstance();
+ public static Template tBigDecimal() {
+ return TBigDecimal;
+ }
+
public static final Template TFloat = FloatTemplate.getInstance();
public static Template tFloat() {
return TFloat;
@@ -105,5 +110,10 @@ public class Templates {
public static Template tByteBuffer() {
return TByteBuffer;
}
+
+ public static final Template TDate = DateTemplate.getInstance();
+ public static Template tDate() {
+ return TDate;
+ }
}
diff --git a/java/src/main/java/org/msgpack/annotation/Ignore.java b/java/src/main/java/org/msgpack/annotation/Ignore.java
index 96a37bb6..e052e58a 100644
--- a/java/src/main/java/org/msgpack/annotation/Ignore.java
+++ b/java/src/main/java/org/msgpack/annotation/Ignore.java
@@ -22,7 +22,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Ignore {
}
diff --git a/java/src/main/java/org/msgpack/annotation/Index.java b/java/src/main/java/org/msgpack/annotation/Index.java
index 7c1b6598..d3b2181f 100644
--- a/java/src/main/java/org/msgpack/annotation/Index.java
+++ b/java/src/main/java/org/msgpack/annotation/Index.java
@@ -22,7 +22,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Index {
int value();
diff --git a/java/src/main/java/org/msgpack/annotation/MessagePackBeans.java b/java/src/main/java/org/msgpack/annotation/MessagePackBeans.java
new file mode 100644
index 00000000..bff1b0d2
--- /dev/null
+++ b/java/src/main/java/org/msgpack/annotation/MessagePackBeans.java
@@ -0,0 +1,35 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
+//
+// 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.
+//
+package org.msgpack.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.msgpack.template.FieldOption;
+
+/**
+ * Annotation for java beans class
+ * @author takeshita
+ *
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface MessagePackBeans {
+ FieldOption value() default FieldOption.DEFAULT;
+}
diff --git a/java/src/main/java/org/msgpack/annotation/Nullable.java b/java/src/main/java/org/msgpack/annotation/Nullable.java
index e6893e72..56aea89e 100644
--- a/java/src/main/java/org/msgpack/annotation/Nullable.java
+++ b/java/src/main/java/org/msgpack/annotation/Nullable.java
@@ -22,7 +22,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Nullable {
}
diff --git a/java/src/main/java/org/msgpack/annotation/Optional.java b/java/src/main/java/org/msgpack/annotation/Optional.java
index 7894f881..a137ec86 100644
--- a/java/src/main/java/org/msgpack/annotation/Optional.java
+++ b/java/src/main/java/org/msgpack/annotation/Optional.java
@@ -22,7 +22,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Optional {
}
diff --git a/java/src/main/java/org/msgpack/annotation/Required.java b/java/src/main/java/org/msgpack/annotation/Required.java
index 16311085..de1d816b 100644
--- a/java/src/main/java/org/msgpack/annotation/Required.java
+++ b/java/src/main/java/org/msgpack/annotation/Required.java
@@ -22,7 +22,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Required {
}
diff --git a/java/src/main/java/org/msgpack/object/RawType.java b/java/src/main/java/org/msgpack/object/RawType.java
index 26f6e0d9..f6866c46 100644
--- a/java/src/main/java/org/msgpack/object/RawType.java
+++ b/java/src/main/java/org/msgpack/object/RawType.java
@@ -1,7 +1,7 @@
//
// MessagePack for Java
//
-// Copyright (C) 2009-2010 FURUHASHI Sadayuki
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -79,7 +79,7 @@ public class RawType extends MessagePackObject {
@Override
public int hashCode() {
- return bytes.hashCode();
+ return Arrays.hashCode(bytes);
}
@Override
diff --git a/java/src/main/java/org/msgpack/template/BeansFieldEntry.java b/java/src/main/java/org/msgpack/template/BeansFieldEntry.java
new file mode 100644
index 00000000..5d5ff816
--- /dev/null
+++ b/java/src/main/java/org/msgpack/template/BeansFieldEntry.java
@@ -0,0 +1,143 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
+//
+// 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.
+//
+package org.msgpack.template;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.*;
+import org.msgpack.*;
+
+/**
+ * Field entry for Java beans property.
+ * @author takeshita
+ *
+ */
+public class BeansFieldEntry implements IFieldEntry {
+
+ PropertyDescriptor desc;
+ FieldOption option = FieldOption.DEFAULT;
+
+ public BeansFieldEntry(PropertyDescriptor desc) {
+ this.desc = desc;
+ }
+
+ @Override
+ public String getName() {
+ return desc.getDisplayName();
+ }
+ public String getGetterName(){
+ return desc.getReadMethod().getName();
+ }
+ public String getSetterName(){
+ return desc.getWriteMethod().getName();
+ }
+
+ @Override
+ public Class> getType() {
+ return desc.getPropertyType();
+ }
+
+ @Override
+ public String getJavaTypeName() {
+ Class> type = getType();
+ if(type.isArray()) {
+ return arrayTypeToString(type);
+ } else {
+ return type.getName();
+ }
+ }
+ static String arrayTypeToString(Class> type) {
+ int dim = 1;
+ Class> baseType = type.getComponentType();
+ while(baseType.isArray()) {
+ baseType = baseType.getComponentType();
+ dim += 1;
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append(baseType.getName());
+ for (int i = 0; i < dim; ++i) {
+ sb.append("[]");
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public Type getGenericType() {
+ return desc.getReadMethod().getGenericReturnType();
+ }
+
+ @Override
+ public FieldOption getOption() {
+ return option;
+ }
+ public void setOption(FieldOption option){
+ this.option = option;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return option != FieldOption.IGNORE;
+ }
+
+ /* (non-Javadoc)
+ * @see org.msgpack.template.IFieldEntry#isRequired()
+ */
+ @Override
+ public boolean isRequired() {
+ return option == FieldOption.REQUIRED;
+ }
+
+ /* (non-Javadoc)
+ * @see org.msgpack.template.IFieldEntry#isOptional()
+ */
+ @Override
+ public boolean isOptional() {
+ return option == FieldOption.OPTIONAL;
+ }
+
+ /* (non-Javadoc)
+ * @see org.msgpack.template.IFieldEntry#isNullable()
+ */
+ @Override
+ public boolean isNullable() {
+ return option == FieldOption.NULLABLE;
+ }
+
+ public Object get(Object target){
+ try {
+ return desc.getReadMethod().invoke(target);
+ } catch (IllegalArgumentException e) {
+ throw new MessageTypeException(e);
+ } catch (IllegalAccessException e) {
+ throw new MessageTypeException(e);
+ } catch (InvocationTargetException e) {
+ throw new MessageTypeException(e);
+ }
+ }
+ public void set(Object target , Object value){
+ try {
+ desc.getWriteMethod().invoke(target, value);
+ } catch (IllegalArgumentException e) {
+ throw new MessageTypeException(e);
+ } catch (IllegalAccessException e) {
+ throw new MessageTypeException(e);
+ } catch (InvocationTargetException e) {
+ throw new MessageTypeException(e);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/java/src/main/java/org/msgpack/template/BeansFieldEntryReader.java b/java/src/main/java/org/msgpack/template/BeansFieldEntryReader.java
new file mode 100644
index 00000000..9d3039b2
--- /dev/null
+++ b/java/src/main/java/org/msgpack/template/BeansFieldEntryReader.java
@@ -0,0 +1,188 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
+//
+// 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.
+//
+package org.msgpack.template;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.msgpack.annotation.Ignore;
+import org.msgpack.annotation.Index;
+import org.msgpack.annotation.MessagePackMessage;
+import org.msgpack.annotation.Nullable;
+import org.msgpack.annotation.Optional;
+import org.msgpack.annotation.Required;
+
+/**
+ * List up Java beans property methods.
+ * @author takeshita
+ *
+ */
+public class BeansFieldEntryReader implements IFieldEntryReader{
+
+
+ public IFieldEntry[] convertFieldEntries(Class> targetClass, FieldList flist) throws NoSuchFieldException {
+ List src = flist.getList();
+ FieldEntry[] result = new FieldEntry[src.size()];
+ for(int i=0; i < src.size(); i++) {
+ FieldList.Entry s = src.get(i);
+ if(s.isAvailable()) {
+ result[i] = new FieldEntry(targetClass.getDeclaredField(s.getName()), s.getOption());
+ } else {
+ result[i] = new FieldEntry();
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public IFieldEntry[] readFieldEntries(Class> targetClass,
+ FieldOption implicitOption) {
+ BeanInfo desc;
+ try {
+ desc = Introspector.getBeanInfo(targetClass);
+ } catch (IntrospectionException e1) {
+ throw new TemplateBuildException("Class must be java beans class:" + targetClass.getName());
+ }
+
+ PropertyDescriptor[] props = desc.getPropertyDescriptors();
+ ArrayList list = new ArrayList();
+ for(int i = 0;i < props.length;i++){
+ PropertyDescriptor pd = props[i];
+ if(!isIgnoreProp(pd)){
+ list.add(pd);
+ }
+ }
+ props = new PropertyDescriptor[list.size()];
+ list.toArray(props);
+
+ BeansFieldEntry[] entries = new BeansFieldEntry[props.length];
+ for(int i = 0;i < props.length;i++){
+ PropertyDescriptor p = props[i];
+ int index = readPropIndex(p);
+ if(index >= 0){
+ if(entries[index] != null){
+ throw new TemplateBuildException("duplicated index: "+index);
+ }
+ if(index >= entries.length){
+ throw new TemplateBuildException("invalid index: "+index);
+ }
+ entries[index] = new BeansFieldEntry(p);
+ props[index] = null;
+ }
+ }
+ int insertIndex = 0;
+ for(int i = 0;i < props.length;i++){
+ PropertyDescriptor p = props[i];
+ if(p != null){
+ while(entries[insertIndex] != null){
+ insertIndex++;
+ }
+ entries[insertIndex] = new BeansFieldEntry(p);
+ }
+
+ }
+ for(int i = 0;i < entries.length;i++){
+ BeansFieldEntry e = entries[i];
+ FieldOption op = readPropOption(e.desc, implicitOption);
+ e.setOption(op);
+ }
+ return entries;
+ }
+
+ public FieldOption readImplicitFieldOption(Class> targetClass) {
+ MessagePackMessage a = targetClass.getAnnotation(MessagePackMessage.class);
+ if(a == null) {
+ return FieldOption.DEFAULT;
+ }
+ return a.value();
+ }
+
+
+ private FieldOption readPropOption(PropertyDescriptor desc, FieldOption implicitOption) {
+
+ FieldOption forGetter = readMethodOption(desc.getReadMethod());
+ if(forGetter != FieldOption.DEFAULT){
+ return forGetter;
+ }
+ FieldOption forSetter = readMethodOption(desc.getWriteMethod());
+ if(forSetter != FieldOption.DEFAULT){
+ return forSetter;
+ }else{
+ return implicitOption;
+ }
+
+ }
+ private FieldOption readMethodOption(Method method){
+
+ if(isAnnotated(method, Ignore.class)) {
+ return FieldOption.IGNORE;
+ } else if(isAnnotated(method, Required.class)) {
+ return FieldOption.REQUIRED;
+ } else if(isAnnotated(method, Optional.class)) {
+ return FieldOption.OPTIONAL;
+ } else if(isAnnotated(method, Nullable.class)) {
+ if(method.getDeclaringClass().isPrimitive()) {
+ return FieldOption.REQUIRED;
+ } else {
+ return FieldOption.NULLABLE;
+ }
+ }
+ return FieldOption.DEFAULT;
+ }
+
+ private int readPropIndex(PropertyDescriptor desc) {
+
+ int forGetter = readMethodIndex(desc.getReadMethod());
+ if(forGetter >= 0){
+ return forGetter;
+ }
+ int forSetter = readMethodIndex(desc.getWriteMethod());
+ return forSetter;
+ }
+ private int readMethodIndex(Method method){
+ Index a = method.getAnnotation(Index.class);
+ if(a == null) {
+ return -1;
+ } else {
+ return a.value();
+ }
+ }
+
+ private boolean isAnnotated(AccessibleObject ao, Class extends Annotation> with) {
+ return ao.getAnnotation(with) != null;
+ }
+ boolean isIgnoreProp(PropertyDescriptor desc){
+ if(desc == null)return true;
+ Method getter = desc.getReadMethod();
+ Method setter = desc.getWriteMethod();
+ return getter == null ||
+ setter == null ||
+ !Modifier.isPublic(getter.getModifiers()) ||
+ !Modifier.isPublic(setter.getModifiers()) ||
+ isAnnotated(getter,Ignore.class) ||
+ isAnnotated(setter, Ignore.class);
+ }
+}
diff --git a/java/src/main/java/org/msgpack/template/BigDecimalTemplate.java b/java/src/main/java/org/msgpack/template/BigDecimalTemplate.java
new file mode 100644
index 00000000..7958f825
--- /dev/null
+++ b/java/src/main/java/org/msgpack/template/BigDecimalTemplate.java
@@ -0,0 +1,61 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
+//
+// 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.
+//
+package org.msgpack.template;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import org.msgpack.MessagePackObject;
+import org.msgpack.MessageTypeException;
+import org.msgpack.Packer;
+import org.msgpack.Template;
+import org.msgpack.Unpacker;
+
+public class BigDecimalTemplate implements Template {
+
+ @Override
+ public void pack(Packer pk, Object target) throws IOException {
+ BigDecimal temp = (BigDecimal) target;
+ try {
+ pk.packString(temp.toString());
+ } catch (NullPointerException e) {
+ throw new MessageTypeException("target is null.", e);
+ }
+ }
+
+ @Override
+ public Object unpack(Unpacker pac, Object to) throws IOException, MessageTypeException {
+ String temp = pac.unpackString();
+ return new BigDecimal(temp);
+ }
+
+ @Override
+ public Object convert(MessagePackObject from, Object to) throws MessageTypeException {
+ String temp = from.asString();
+ return new BigDecimal(temp);
+ }
+
+ static public BigDecimalTemplate getInstance() {
+ return instance;
+ }
+
+ static final BigDecimalTemplate instance = new BigDecimalTemplate();
+
+ static {
+ TemplateRegistry.register(BigDecimal.class, instance);
+ }
+}
diff --git a/java/src/main/java/org/msgpack/template/BuiltInTemplateLoader.java b/java/src/main/java/org/msgpack/template/BuiltInTemplateLoader.java
index 9ac9a8ed..4b8d618c 100644
--- a/java/src/main/java/org/msgpack/template/BuiltInTemplateLoader.java
+++ b/java/src/main/java/org/msgpack/template/BuiltInTemplateLoader.java
@@ -1,7 +1,7 @@
//
// MessagePack for Java
//
-// Copyright (C) 2009-2010 FURUHASHI Sadayuki
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@ public class BuiltInTemplateLoader {
public static void load() {
AnyTemplate.getInstance();
BigIntegerTemplate.getInstance();
+ BigDecimalTemplate.getInstance();
BooleanArrayTemplate.getInstance();
BooleanTemplate.getInstance();
ByteArrayTemplate.getInstance();
@@ -28,6 +29,7 @@ public class BuiltInTemplateLoader {
ByteTemplate.getInstance();
DoubleArrayTemplate.getInstance();
DoubleTemplate.getInstance();
+ DateTemplate.getInstance();
FloatArrayTemplate.getInstance();
FloatTemplate.getInstance();
IntArrayTemplate.getInstance();
diff --git a/java/src/main/java/org/msgpack/template/DateTemplate.java b/java/src/main/java/org/msgpack/template/DateTemplate.java
new file mode 100644
index 00000000..26adde68
--- /dev/null
+++ b/java/src/main/java/org/msgpack/template/DateTemplate.java
@@ -0,0 +1,57 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
+//
+// 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.
+//
+package org.msgpack.template;
+
+import java.io.IOException;
+import java.util.Date;
+import org.msgpack.MessagePackObject;
+import org.msgpack.MessageTypeException;
+import org.msgpack.Packer;
+import org.msgpack.Template;
+import org.msgpack.Unpacker;
+
+public class DateTemplate implements Template {
+
+ @Override
+ public void pack(Packer pk, Object target) throws IOException {
+ Date temp = (Date) target;
+ pk.packLong(temp.getTime());
+ }
+
+ @Override
+ public Object unpack(Unpacker pac, Object to) throws IOException, MessageTypeException {
+ Long temp = pac.unpackLong();
+ return new Date(temp);
+ }
+
+ @Override
+ public Object convert(MessagePackObject from, Object to) throws MessageTypeException {
+ Long temp = from.asLong();
+ return new Date(temp);
+ }
+
+ static public DateTemplate getInstance() {
+ return instance;
+ }
+
+ static final DateTemplate instance = new DateTemplate();
+
+ static {
+ TemplateRegistry.register(Date.class, instance);
+ }
+}
diff --git a/java/src/main/java/org/msgpack/template/DefaultTemplate.java b/java/src/main/java/org/msgpack/template/DefaultTemplate.java
index 7784eb27..f94e2f13 100644
--- a/java/src/main/java/org/msgpack/template/DefaultTemplate.java
+++ b/java/src/main/java/org/msgpack/template/DefaultTemplate.java
@@ -1,7 +1,7 @@
//
// MessagePack for Java
//
-// Copyright (C) 2009-2010 FURUHASHI Sadayuki
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -50,7 +50,7 @@ public class DefaultTemplate implements Template {
}
Template tmpl = TemplateRegistry.tryLookup(lookupType);
if(tmpl == this || tmpl == null) {
- throw new MessageTypeException();
+ throw new MessageTypeException("Template lookup fail: " + lookupType.getClass().getName());
}
tmpl.pack(pk, target);
}
@@ -69,7 +69,7 @@ public class DefaultTemplate implements Template {
}
Template tmpl = TemplateRegistry.tryLookup(lookupType);
if(tmpl == this || tmpl == null) {
- throw new MessageTypeException();
+ throw new MessageTypeException("Template lookup fail: " + lookupType.getClass().getName());
}
return tmpl.unpack(pac, to);
}
@@ -88,7 +88,7 @@ public class DefaultTemplate implements Template {
}
Template tmpl = TemplateRegistry.tryLookup(lookupType);
if(tmpl == this || tmpl == null) {
- throw new MessageTypeException();
+ throw new MessageTypeException("Template lookup fail: " + lookupType.getClass().getName());
}
return tmpl.convert(from, to);
}
diff --git a/java/src/main/java/org/msgpack/template/FieldEntry.java b/java/src/main/java/org/msgpack/template/FieldEntry.java
new file mode 100644
index 00000000..a8437403
--- /dev/null
+++ b/java/src/main/java/org/msgpack/template/FieldEntry.java
@@ -0,0 +1,143 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
+//
+// 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.
+//
+package org.msgpack.template;
+
+import java.io.IOException;
+import java.lang.reflect.*;
+import java.lang.annotation.*;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import org.msgpack.*;
+import org.msgpack.annotation.*;
+
+public class FieldEntry implements IFieldEntry {
+ private Field field;
+ private FieldOption option;
+
+ public FieldEntry() {
+ this.field = null;
+ this.option = FieldOption.IGNORE;
+ }
+
+ public FieldEntry(FieldEntry e) {
+ this.field = e.field;
+ this.option = e.option;
+ }
+
+ public FieldEntry(Field field, FieldOption option) {
+ this.field = field;
+ this.option = option;
+ }
+
+ public Field getField() {
+ return field;
+ }
+
+ /* (non-Javadoc)
+ * @see org.msgpack.template.IFieldEntry#getName()
+ */
+ @Override
+ public String getName() {
+ return field.getName();
+ }
+
+ /* (non-Javadoc)
+ * @see org.msgpack.template.IFieldEntry#getType()
+ */
+ @Override
+ public Class> getType() {
+ return field.getType();
+ }
+
+ /* (non-Javadoc)
+ * @see org.msgpack.template.IFieldEntry#getJavaTypeName()
+ */
+ @Override
+ public String getJavaTypeName() {
+ Class> type = field.getType();
+ if(type.isArray()) {
+ return arrayTypeToString(type);
+ } else {
+ return type.getName();
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.msgpack.template.IFieldEntry#getGenericType()
+ */
+ @Override
+ public Type getGenericType() {
+ return field.getGenericType();
+ }
+
+ /* (non-Javadoc)
+ * @see org.msgpack.template.IFieldEntry#getOption()
+ */
+ @Override
+ public FieldOption getOption() {
+ return option;
+ }
+
+ /* (non-Javadoc)
+ * @see org.msgpack.template.IFieldEntry#isAvailable()
+ */
+ @Override
+ public boolean isAvailable() {
+ return option != FieldOption.IGNORE;
+ }
+
+ /* (non-Javadoc)
+ * @see org.msgpack.template.IFieldEntry#isRequired()
+ */
+ @Override
+ public boolean isRequired() {
+ return option == FieldOption.REQUIRED;
+ }
+
+ /* (non-Javadoc)
+ * @see org.msgpack.template.IFieldEntry#isOptional()
+ */
+ @Override
+ public boolean isOptional() {
+ return option == FieldOption.OPTIONAL;
+ }
+
+ /* (non-Javadoc)
+ * @see org.msgpack.template.IFieldEntry#isNullable()
+ */
+ @Override
+ public boolean isNullable() {
+ return option == FieldOption.NULLABLE;
+ }
+
+ static String arrayTypeToString(Class> type) {
+ int dim = 1;
+ Class> baseType = type.getComponentType();
+ while(baseType.isArray()) {
+ baseType = baseType.getComponentType();
+ dim += 1;
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append(baseType.getName());
+ for (int i = 0; i < dim; ++i) {
+ sb.append("[]");
+ }
+ return sb.toString();
+ }
+}
\ No newline at end of file
diff --git a/java/src/main/java/org/msgpack/template/FieldEntryReader.java b/java/src/main/java/org/msgpack/template/FieldEntryReader.java
new file mode 100644
index 00000000..81114a51
--- /dev/null
+++ b/java/src/main/java/org/msgpack/template/FieldEntryReader.java
@@ -0,0 +1,182 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
+//
+// 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.
+//
+package org.msgpack.template;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.msgpack.annotation.Ignore;
+import org.msgpack.annotation.Index;
+import org.msgpack.annotation.MessagePackMessage;
+import org.msgpack.annotation.Nullable;
+import org.msgpack.annotation.Optional;
+import org.msgpack.annotation.Required;
+
+public class FieldEntryReader implements IFieldEntryReader{
+
+
+ public IFieldEntry[] convertFieldEntries(Class> targetClass, FieldList flist) throws NoSuchFieldException {
+ List src = flist.getList();
+ FieldEntry[] result = new FieldEntry[src.size()];
+ for(int i=0; i < src.size(); i++) {
+ FieldList.Entry s = src.get(i);
+ if(s.isAvailable()) {
+ result[i] = new FieldEntry(targetClass.getDeclaredField(s.getName()), s.getOption());
+ } else {
+ result[i] = new FieldEntry();
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public IFieldEntry[] readFieldEntries(Class> targetClass,
+ FieldOption implicitOption) {
+ Field[] allFields = readAllFields(targetClass);
+
+ /* index:
+ * @Index(0) int field_a; // 0
+ * int field_b; // 1
+ * @Index(3) int field_c; // 3
+ * int field_d; // 4
+ * @Index(2) int field_e; // 2
+ * int field_f; // 5
+ */
+ List indexed = new ArrayList();
+ int maxIndex = -1;
+ for(Field f : allFields) {
+ FieldOption opt = readFieldOption(f, implicitOption);
+ if(opt == FieldOption.IGNORE) {
+ // skip
+ continue;
+ }
+
+ int index = readFieldIndex(f, maxIndex);
+
+ if(indexed.size() > index && indexed.get(index) != null) {
+ throw new TemplateBuildException("duplicated index: "+index);
+ }
+ if(index < 0) {
+ throw new TemplateBuildException("invalid index: "+index);
+ }
+
+ while(indexed.size() <= index) {
+ indexed.add(null);
+ }
+ indexed.set(index, new FieldEntry(f, opt));
+
+ if(maxIndex < index) {
+ maxIndex = index;
+ }
+ }
+
+ FieldEntry[] result = new FieldEntry[maxIndex+1];
+ for(int i=0; i < indexed.size(); i++) {
+ FieldEntry e = indexed.get(i);
+ if(e == null) {
+ result[i] = new FieldEntry();
+ } else {
+ result[i] = e;
+ }
+ }
+
+ return result;
+ }
+
+ public FieldOption readImplicitFieldOption(Class> targetClass) {
+ MessagePackMessage a = targetClass.getAnnotation(MessagePackMessage.class);
+ if(a == null) {
+ return FieldOption.DEFAULT;
+ }
+ return a.value();
+ }
+
+ private Field[] readAllFields(Class> targetClass) {
+ // order: [fields of super class, ..., fields of this class]
+ List succ = new ArrayList();
+ int total = 0;
+ for(Class> c = targetClass; c != Object.class; c = c.getSuperclass()) {
+ Field[] fields = c.getDeclaredFields();
+ total += fields.length;
+ succ.add(fields);
+ }
+ Field[] result = new Field[total];
+ int off = 0;
+ for(int i=succ.size()-1; i >= 0; i--) {
+ Field[] fields = succ.get(i);
+ System.arraycopy(fields, 0, result, off, fields.length);
+ off += fields.length;
+ }
+ return result;
+ }
+
+ private static FieldOption readFieldOption(Field field, FieldOption implicitOption) {
+ int mod = field.getModifiers();
+ if(Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
+ return FieldOption.IGNORE;
+ }
+
+ if(isAnnotated(field, Ignore.class)) {
+ return FieldOption.IGNORE;
+ } else if(isAnnotated(field, Required.class)) {
+ return FieldOption.REQUIRED;
+ } else if(isAnnotated(field, Optional.class)) {
+ return FieldOption.OPTIONAL;
+ } else if(isAnnotated(field, Nullable.class)) {
+ if(field.getDeclaringClass().isPrimitive()) {
+ return FieldOption.REQUIRED;
+ } else {
+ return FieldOption.NULLABLE;
+ }
+ }
+
+ if(implicitOption != FieldOption.DEFAULT) {
+ return implicitOption;
+ }
+
+ // default mode:
+ // transient : Ignore
+ // public : Required
+ // others : Ignore
+ if(Modifier.isTransient(mod)) {
+ return FieldOption.IGNORE;
+ } else if(Modifier.isPublic(mod)) {
+ return FieldOption.REQUIRED;
+ } else {
+ return FieldOption.IGNORE;
+ }
+ }
+
+ private static int readFieldIndex(Field field, int maxIndex) {
+ Index a = field.getAnnotation(Index.class);
+ if(a == null) {
+ return maxIndex + 1;
+ } else {
+ return a.value();
+ }
+ }
+
+ private static boolean isAnnotated(AccessibleObject ao, Class extends Annotation> with) {
+ return ao.getAnnotation(with) != null;
+ }
+
+}
diff --git a/java/src/main/java/org/msgpack/template/FieldList.java b/java/src/main/java/org/msgpack/template/FieldList.java
index daf59f5b..a5b141d9 100644
--- a/java/src/main/java/org/msgpack/template/FieldList.java
+++ b/java/src/main/java/org/msgpack/template/FieldList.java
@@ -43,19 +43,19 @@ public class FieldList {
return option;
}
- boolean isAvailable() {
+ public boolean isAvailable() {
return this.option != FieldOption.IGNORE;
}
- boolean isRequired() {
+ public boolean isRequired() {
return this.option == FieldOption.REQUIRED;
}
- boolean isOptional() {
+ public boolean isOptional() {
return this.option == FieldOption.OPTIONAL;
}
- boolean isNullable() {
+ public boolean isNullable() {
return this.option == FieldOption.NULLABLE;
}
}
@@ -89,7 +89,7 @@ public class FieldList {
}
}
- List getList() {
+ public List getList() {
return list;
}
}
diff --git a/java/src/main/java/org/msgpack/template/IFieldEntry.java b/java/src/main/java/org/msgpack/template/IFieldEntry.java
new file mode 100644
index 00000000..23700c67
--- /dev/null
+++ b/java/src/main/java/org/msgpack/template/IFieldEntry.java
@@ -0,0 +1,42 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
+//
+// 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.
+//
+package org.msgpack.template;
+
+import java.lang.reflect.Type;
+
+public interface IFieldEntry {
+
+ public abstract String getName();
+
+ public abstract Class> getType();
+
+ public abstract String getJavaTypeName();
+
+ public abstract Type getGenericType();
+
+ public abstract FieldOption getOption();
+
+ public abstract boolean isAvailable();
+
+ public abstract boolean isRequired();
+
+ public abstract boolean isOptional();
+
+ public abstract boolean isNullable();
+
+}
\ No newline at end of file
diff --git a/java/src/main/java/org/msgpack/template/IFieldEntryReader.java b/java/src/main/java/org/msgpack/template/IFieldEntryReader.java
new file mode 100644
index 00000000..fe3024a7
--- /dev/null
+++ b/java/src/main/java/org/msgpack/template/IFieldEntryReader.java
@@ -0,0 +1,25 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
+//
+// 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.
+//
+package org.msgpack.template;
+
+public interface IFieldEntryReader {
+
+ public IFieldEntry[] convertFieldEntries(Class> targetClass, FieldList flist) throws NoSuchFieldException;
+ public IFieldEntry[] readFieldEntries(Class> targetClass, FieldOption implicitOption);
+ public FieldOption readImplicitFieldOption(Class> targetClass) ;
+}
diff --git a/java/src/main/java/org/msgpack/template/JavassistTemplateBuilder.java b/java/src/main/java/org/msgpack/template/JavassistTemplateBuilder.java
deleted file mode 100644
index 38bb998f..00000000
--- a/java/src/main/java/org/msgpack/template/JavassistTemplateBuilder.java
+++ /dev/null
@@ -1,592 +0,0 @@
-//
-// MessagePack for Java
-//
-// Copyright (C) 2009-2010 FURUHASHI Sadayuki
-//
-// 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.
-//
-package org.msgpack.template;
-
-import java.io.IOException;
-import java.lang.reflect.Array;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Type;
-
-import org.msgpack.*;
-
-import javassist.CannotCompileException;
-import javassist.ClassPool;
-import javassist.CtClass;
-import javassist.CtConstructor;
-import javassist.CtMethod;
-import javassist.CtNewConstructor;
-import javassist.CtNewMethod;
-import javassist.LoaderClassPath;
-import javassist.NotFoundException;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class JavassistTemplateBuilder extends TemplateBuilder {
- private static Logger LOG = LoggerFactory.getLogger(JavassistTemplateBuilder.class);
-
- private static JavassistTemplateBuilder instance;
-
- public synchronized static JavassistTemplateBuilder getInstance() {
- if(instance == null) {
- instance = new JavassistTemplateBuilder();
- }
- return instance;
- }
-
- public static void addClassLoader(ClassLoader cl) {
- getInstance().pool.appendClassPath(new LoaderClassPath(cl));
- }
-
- private JavassistTemplateBuilder() {
- this.pool = ClassPool.getDefault();
- }
-
- protected ClassPool pool;
-
- private int seqId = 0;
-
- CtClass makeCtClass(String className) {
- return pool.makeClass(className);
- }
-
- CtClass getCtClass(String className) throws NotFoundException {
- return pool.get(className);
- }
-
- int nextSeqId() {
- return seqId++;
- }
-
- private static abstract class BuildContextBase {
- protected JavassistTemplateBuilder director;
-
- protected String tmplName;
-
- protected CtClass tmplCtClass;
-
- protected abstract void setSuperClass() throws CannotCompileException, NotFoundException;
-
- protected abstract void buildConstructor() throws CannotCompileException, NotFoundException;
-
- protected void buildMethodInit() { }
-
- protected abstract String buildPackMethodBody();
-
- protected abstract String buildUnpackMethodBody();
-
- protected abstract String buildConvertMethodBody();
-
- protected abstract Template buildInstance(Class> c) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException;
-
- public BuildContextBase(JavassistTemplateBuilder director) {
- this.director = director;
- }
-
- protected Template build(final String className) {
- try {
- reset(className);
- buildClass();
- buildConstructor();
- buildMethodInit();
- buildPackMethod();
- buildUnpackMethod();
- buildConvertMethod();
- return buildInstance(createClass());
- } catch (Exception e) {
- String code = getBuiltString();
- if(code != null) {
- LOG.error("builder: " + code, e);
- throw new TemplateBuildException("cannot compile: " + code, e);
- } else {
- throw new TemplateBuildException(e);
- }
- }
- }
-
- protected void reset(String className) {
- tmplName = className + "_$$_Template" + director.nextSeqId();
- tmplCtClass = director.makeCtClass(tmplName);
- }
-
- protected void buildClass() throws CannotCompileException, NotFoundException {
- setSuperClass();
- tmplCtClass.addInterface(director.getCtClass(Template.class.getName()));
- }
-
- protected void buildPackMethod() throws CannotCompileException, NotFoundException {
- String mbody = buildPackMethodBody();
- int mod = javassist.Modifier.PUBLIC;
- CtClass returnType = CtClass.voidType;
- String mname = "pack";
- CtClass[] paramTypes = new CtClass[] {
- director.getCtClass(Packer.class.getName()),
- director.getCtClass(Object.class.getName())
- };
- CtClass[] exceptTypes = new CtClass[] {
- director.getCtClass(IOException.class.getName())
- };
- CtMethod newCtMethod = CtNewMethod.make(
- mod, returnType, mname,
- paramTypes, exceptTypes, mbody, tmplCtClass);
- tmplCtClass.addMethod(newCtMethod);
- }
-
- protected void buildUnpackMethod() throws CannotCompileException, NotFoundException {
- String mbody = buildUnpackMethodBody();
- int mod = javassist.Modifier.PUBLIC;
- CtClass returnType = director.getCtClass(Object.class.getName());
- String mname = "unpack";
- CtClass[] paramTypes = new CtClass[] {
- director.getCtClass(Unpacker.class.getName()),
- director.getCtClass(Object.class.getName())
- };
- CtClass[] exceptTypes = new CtClass[] {
- director.getCtClass(MessageTypeException.class.getName())
- };
- CtMethod newCtMethod = CtNewMethod.make(
- mod, returnType, mname,
- paramTypes, exceptTypes, mbody, tmplCtClass);
- tmplCtClass.addMethod(newCtMethod);
- }
-
- protected void buildConvertMethod() throws CannotCompileException, NotFoundException {
- String mbody = buildConvertMethodBody();
- int mod = javassist.Modifier.PUBLIC;
- CtClass returnType = director.getCtClass(Object.class.getName());
- String mname = "convert";
- CtClass[] paramTypes = new CtClass[] {
- director.getCtClass(MessagePackObject.class.getName()),
- director.getCtClass(Object.class.getName())
- };
- CtClass[] exceptTypes = new CtClass[] {
- director.getCtClass(MessageTypeException.class.getName())
- };
- CtMethod newCtMethod = CtNewMethod.make(
- mod, returnType, mname,
- paramTypes, exceptTypes, mbody, tmplCtClass);
- tmplCtClass.addMethod(newCtMethod);
- }
-
- protected Class> createClass() throws CannotCompileException {
- return (Class>) tmplCtClass.toClass(null, null);
- }
-
- protected StringBuilder stringBuilder = null;
-
- protected void resetStringBuilder() {
- stringBuilder = new StringBuilder();
- }
-
- protected void buildString(String str) {
- stringBuilder.append(str);
- }
-
- protected void buildString(String format, Object... args) {
- stringBuilder.append(String.format(format, args));
- }
-
- protected String getBuiltString() {
- if(stringBuilder == null) {
- return null;
- }
- return stringBuilder.toString();
- }
- }
-
- public static abstract class JavassistTemplate extends AbstractTemplate {
- public Class> targetClass;
- public Template[] templates;
-
- public JavassistTemplate(Class> targetClass, Template[] templates) {
- this.targetClass = targetClass;
- this.templates = templates;
- }
- }
-
- private static class BuildContext extends BuildContextBase {
- protected FieldEntry[] entries;
- protected Class> origClass;
- protected String origName;
- protected Template[] templates;
- protected int minimumArrayLength;
-
- public BuildContext(JavassistTemplateBuilder director) {
- super(director);
- }
-
- public Template buildTemplate(Class> targetClass, FieldEntry[] entries, Template[] templates) {
- this.entries = entries;
- this.templates = templates;
- this.origClass = targetClass;
- this.origName = this.origClass.getName();
- return build(this.origName);
- }
-
- protected void setSuperClass() throws CannotCompileException, NotFoundException {
- this.tmplCtClass.setSuperclass(
- director.getCtClass(JavassistTemplate.class.getName()));
- }
-
- protected void buildConstructor() throws CannotCompileException, NotFoundException {
- // Constructor(Class targetClass, Template[] templates)
- CtConstructor newCtCons = CtNewConstructor.make(
- new CtClass[] {
- director.getCtClass(Class.class.getName()),
- director.getCtClass(Template.class.getName()+"[]")
- },
- new CtClass[0],
- this.tmplCtClass);
- this.tmplCtClass.addConstructor(newCtCons);
- }
-
- protected Template buildInstance(Class> c) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
- Constructor> cons = c.getConstructor(new Class[] {
- Class.class,
- Template[].class
- });
- Object tmpl = cons.newInstance(new Object[] {
- this.origClass,
- this.templates
- });
- return (Template)tmpl;
- }
-
- protected void buildMethodInit() {
- this.minimumArrayLength = 0;
- for(int i=0; i < entries.length; i++) {
- FieldEntry e = entries[i];
- if(e.isRequired() || e.isNullable()) {
- this.minimumArrayLength = i+1;
- }
- }
- }
-
- protected String buildPackMethodBody() {
- resetStringBuilder();
- buildString("{");
- buildString("%s _$$_t = (%s)$2;", this.origName, this.origName);
- buildString("$1.packArray(%d);", entries.length);
- for(int i=0; i < entries.length; i++) {
- FieldEntry e = entries[i];
- if(!e.isAvailable()) {
- buildString("$1.packNil();");
- continue;
- }
- Class> type = e.getType();
- if(type.isPrimitive()) {
- buildString("$1.%s(_$$_t.%s);", primitivePackName(type), e.getName());
- } else {
- buildString("if(_$$_t.%s == null) {", e.getName());
- if(!e.isNullable() && !e.isOptional()) {
- buildString("throw new %s();", MessageTypeException.class.getName());
- } else {
- buildString("$1.packNil();");
- }
- buildString("} else {");
- buildString(" this.templates[%d].pack($1, _$$_t.%s);", i, e.getName());
- buildString("}");
- }
- }
- buildString("}");
- return getBuiltString();
- }
-
- protected String buildUnpackMethodBody() {
- resetStringBuilder();
- buildString("{ ");
-
- buildString("%s _$$_t;", this.origName);
- buildString("if($2 == null) {");
- buildString(" _$$_t = new %s();", this.origName);
- buildString("} else {");
- buildString(" _$$_t = (%s)$2;", this.origName);
- buildString("}");
-
- buildString("int length = $1.unpackArray();");
- buildString("if(length < %d) {", this.minimumArrayLength);
- buildString(" throw new %s();", MessageTypeException.class.getName());
- buildString("}");
-
- int i;
- for(i=0; i < this.minimumArrayLength; i++) {
- FieldEntry e = entries[i];
- if(!e.isAvailable()) {
- buildString("$1.unpackObject();");
- continue;
- }
-
- buildString("if($1.tryUnpackNull()) {");
- if(e.isRequired()) {
- // Required + nil => exception
- buildString("throw new %s();", MessageTypeException.class.getName());
- } else if(e.isOptional()) {
- // Optional + nil => keep default value
- } else { // Nullable
- // Nullable + nil => set null
- buildString("_$$_t.%s = null;", e.getName());
- }
- buildString("} else {");
- Class> type = e.getType();
- if(type.isPrimitive()) {
- buildString("_$$_t.%s = $1.%s();", e.getName(), primitiveUnpackName(type));
- } else {
- buildString("_$$_t.%s = (%s)this.templates[%d].unpack($1, _$$_t.%s);", e.getName(), e.getJavaTypeName(), i, e.getName());
- }
- buildString("}");
- }
-
- for(; i < entries.length; i++) {
- buildString("if(length <= %d) { return _$$_t; }", i);
-
- FieldEntry e = entries[i];
- if(!e.isAvailable()) {
- buildString("$1.unpackObject();");
- continue;
- }
-
- buildString("if($1.tryUnpackNull()) {");
- // this is Optional field becaue i >= minimumArrayLength
- // Optional + nil => keep default value
- buildString("} else {");
- Class> type = e.getType();
- if(type.isPrimitive()) {
- buildString("_$$_t.%s = $1.%s();", e.getName(), primitiveUnpackName(type));
- } else {
- buildString("_$$_t.%s = (%s)this.templates[%d].unpack($1, _$$_t.%s);", e.getName(), e.getJavaTypeName(), i, e.getName());
- }
- buildString("}");
- }
-
- // latter entries are all Optional + nil => keep default value
-
- buildString("for(int i=%d; i < length; i++) {", i);
- buildString(" $1.unpackObject();");
- buildString("}");
-
- buildString("return _$$_t;");
-
- buildString("}");
- return getBuiltString();
- }
-
- protected String buildConvertMethodBody() {
- resetStringBuilder();
- buildString("{ ");
-
- buildString("%s _$$_t;", this.origName);
- buildString("if($2 == null) {");
- buildString(" _$$_t = new %s();", this.origName);
- buildString("} else {");
- buildString(" _$$_t = (%s)$2;", this.origName);
- buildString("}");
-
- buildString("%s[] array = $1.asArray();", MessagePackObject.class.getName());
- buildString("int length = array.length;");
- buildString("if(length < %d) {", this.minimumArrayLength);
- buildString(" throw new %s();", MessageTypeException.class.getName());
- buildString("}");
-
- buildString("%s obj;", MessagePackObject.class.getName());
-
- int i;
- for(i=0; i < this.minimumArrayLength; i++) {
- FieldEntry e = entries[i];
- if(!e.isAvailable()) {
- continue;
- }
-
- buildString("obj = array[%d];", i);
- buildString("if(obj.isNil()) {");
- if(e.isRequired()) {
- // Required + nil => exception
- buildString("throw new %s();", MessageTypeException.class.getName());
- } else if(e.isOptional()) {
- // Optional + nil => keep default value
- } else { // Nullable
- // Nullable + nil => set null
- buildString("_$$_t.%s = null;", e.getName());
- }
- buildString("} else {");
- Class> type = e.getType();
- if(type.isPrimitive()) {
- buildString("_$$_t.%s = obj.%s();", e.getName(), primitiveConvertName(type));
- } else {
- buildString("_$$_t.%s = (%s)this.templates[%d].convert(obj, _$$_t.%s);", e.getName(), e.getJavaTypeName(), i, e.getName());
- }
- buildString("}");
- }
-
- for(; i < entries.length; i++) {
- buildString("if(length <= %d) { return _$$_t; }", i);
-
- FieldEntry e = entries[i];
- if(!e.isAvailable()) {
- continue;
- }
-
- buildString("obj = array[%d];", i);
- buildString("if(obj.isNil()) {");
- // this is Optional field becaue i >= minimumArrayLength
- // Optional + nil => keep default value
- buildString("} else {");
- Class> type = e.getType();
- if(type.isPrimitive()) {
- buildString("_$$_t.%s = obj.%s();", e.getName(), primitiveConvertName(type));
- } else {
- buildString("_$$_t.%s = (%s)this.templates[%d].convert(obj, _$$_t.%s);", e.getName(), e.getJavaTypeName(), i, e.getName());
- }
- buildString("}");
- }
-
- // latter entries are all Optional + nil => keep default value
-
- buildString("return _$$_t;");
-
- buildString("}");
- return getBuiltString();
- }
-
- protected String primitivePackName(Class> type) {
- if(type == boolean.class) {
- return "packBoolean";
- } else if(type == byte.class) {
- return "packByte";
- } else if(type == short.class) {
- return "packShort";
- } else if(type == int.class) {
- return "packInt";
- } else if(type == long.class) {
- return "packLong";
- } else if(type == float.class) {
- return "packFloat";
- } else if(type == double.class) {
- return "packDouble";
- }
- return null;
- }
-
- protected String primitiveUnpackName(Class> type) {
- if(type == boolean.class) {
- return "unpackBoolean";
- } else if(type == byte.class) {
- return "unpackByte";
- } else if(type == short.class) {
- return "unpackShort";
- } else if(type == int.class) {
- return "unpackInt";
- } else if(type == long.class) {
- return "unpackLong";
- } else if(type == float.class) {
- return "unpackFloat";
- } else if(type == double.class) {
- return "unpackDouble";
- }
- return null;
- }
-
- protected String primitiveConvertName(Class> type) {
- if(type == boolean.class) {
- return "asBoolean";
- } else if(type == byte.class) {
- return "asByte";
- } else if(type == short.class) {
- return "asShort";
- } else if(type == int.class) {
- return "asInt";
- } else if(type == long.class) {
- return "asLong";
- } else if(type == float.class) {
- return "asFloat";
- } else if(type == double.class) {
- return "asDouble";
- }
- return null;
- }
- }
-
- public Template buildTemplate(Class> targetClass, FieldEntry[] entries) {
- // FIXME private / packagefields
- //for(FieldEntry e : entries) {
- // Field f = e.getField();
- // int mod = f.getModifiers();
- // if(!Modifier.isPublic(mod)) {
- // f.setAccessible(true);
- // }
- //}
-
- Template[] tmpls = new Template[entries.length];
- for(int i=0; i < entries.length; i++) {
- FieldEntry e = entries[i];
- if(!e.isAvailable()) {
- tmpls[i] = null;
- } else {
- Template tmpl = TemplateRegistry.lookup(e.getGenericType(), true);
- tmpls[i] = tmpl;
- }
- }
-
- BuildContext bc = new BuildContext(this);
- return bc.buildTemplate(targetClass, entries, tmpls);
- }
-
- static class JavassistOrdinalEnumTemplate extends ReflectionTemplateBuilder.ReflectionOrdinalEnumTemplate {
- JavassistOrdinalEnumTemplate(Enum>[] entries) {
- super(entries);
- }
- }
-
- public Template buildOrdinalEnumTemplate(Class> targetClass, Enum>[] entries) {
- return new JavassistOrdinalEnumTemplate(entries);
- }
-
- public Template buildArrayTemplate(Type arrayType, Type genericBaseType, Class> baseClass, int dim) {
- if(dim == 1) {
- if(baseClass == boolean.class) {
- return BooleanArrayTemplate.getInstance();
- } else if(baseClass == short.class) {
- return ShortArrayTemplate.getInstance();
- } else if(baseClass == int.class) {
- return IntArrayTemplate.getInstance();
- } else if(baseClass == long.class) {
- return LongArrayTemplate.getInstance();
- } else if(baseClass == float.class) {
- return FloatArrayTemplate.getInstance();
- } else if(baseClass == double.class) {
- return DoubleArrayTemplate.getInstance();
- } else {
- // FIXME
- Template baseTemplate = TemplateRegistry.lookup(genericBaseType);
- return new ReflectionTemplateBuilder.ReflectionObjectArrayTemplate(baseClass, baseTemplate);
- }
- } else if(dim == 2) {
- // FIXME
- Class> componentClass = Array.newInstance(baseClass, 0).getClass();
- Template componentTemplate = buildArrayTemplate(arrayType, genericBaseType, baseClass, dim-1);
- return new ReflectionTemplateBuilder.ReflectionMultidimentionalArrayTemplate(componentClass, componentTemplate);
- } else {
- // FIXME
- ReflectionTemplateBuilder.ReflectionMultidimentionalArrayTemplate componentTemplate = (ReflectionTemplateBuilder.ReflectionMultidimentionalArrayTemplate)
- buildArrayTemplate(arrayType, genericBaseType, baseClass, dim-1);
- Class> componentClass = Array.newInstance(componentTemplate.getComponentClass(), 0).getClass();
- return new ReflectionTemplateBuilder.ReflectionMultidimentionalArrayTemplate(componentClass, componentTemplate);
- }
- }
-}
-
diff --git a/java/src/main/java/org/msgpack/template/TemplateBuildException.java b/java/src/main/java/org/msgpack/template/TemplateBuildException.java
index c4c99566..f8560d1f 100644
--- a/java/src/main/java/org/msgpack/template/TemplateBuildException.java
+++ b/java/src/main/java/org/msgpack/template/TemplateBuildException.java
@@ -1,7 +1,7 @@
//
// MessagePack for Java
//
-// Copyright (C) 2009-2010 FURUHASHI Sadayuki
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
diff --git a/java/src/main/java/org/msgpack/template/TemplateBuilder.java b/java/src/main/java/org/msgpack/template/TemplateBuilder.java
deleted file mode 100644
index e3d25b29..00000000
--- a/java/src/main/java/org/msgpack/template/TemplateBuilder.java
+++ /dev/null
@@ -1,381 +0,0 @@
-//
-// MessagePack for Java
-//
-// Copyright (C) 2009-2010 FURUHASHI Sadayuki
-//
-// 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.
-//
-package org.msgpack.template;
-
-import java.io.IOException;
-import java.lang.reflect.*;
-import java.lang.annotation.*;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.EnumSet;
-import org.msgpack.*;
-import org.msgpack.annotation.*;
-
-public abstract class TemplateBuilder {
- public static class FieldEntry {
- private Field field;
- private FieldOption option;
-
- public FieldEntry() {
- this.field = null;
- this.option = FieldOption.IGNORE;
- }
-
- public FieldEntry(FieldEntry e) {
- this.field = e.field;
- this.option = e.option;
- }
-
- public FieldEntry(Field field, FieldOption option) {
- this.field = field;
- this.option = option;
- }
-
- public Field getField() {
- return field;
- }
-
- public String getName() {
- return field.getName();
- }
-
- public Class> getType() {
- return field.getType();
- }
-
- public String getJavaTypeName() {
- Class> type = field.getType();
- if(type.isArray()) {
- return arrayTypeToString(type);
- } else {
- return type.getName();
- }
- }
-
- public Type getGenericType() {
- return field.getGenericType();
- }
-
- public FieldOption getOption() {
- return option;
- }
-
- public boolean isAvailable() {
- return option != FieldOption.IGNORE;
- }
-
- public boolean isRequired() {
- return option == FieldOption.REQUIRED;
- }
-
- public boolean isOptional() {
- return option == FieldOption.OPTIONAL;
- }
-
- public boolean isNullable() {
- return option == FieldOption.NULLABLE;
- }
-
- static String arrayTypeToString(Class> type) {
- int dim = 1;
- Class> baseType = type.getComponentType();
- while(baseType.isArray()) {
- baseType = baseType.getComponentType();
- dim += 1;
- }
- StringBuilder sb = new StringBuilder();
- sb.append(baseType.getName());
- for (int i = 0; i < dim; ++i) {
- sb.append("[]");
- }
- return sb.toString();
- }
- }
-
- // Override this method
- public abstract Template buildTemplate(Class> targetClass, FieldEntry[] entries);
-
- // Override this method
- public abstract Template buildOrdinalEnumTemplate(Class> targetClass, Enum>[] entries);
-
- // Override this method
- public abstract Template buildArrayTemplate(Type arrayType, Type genericBaseType, Class> baseClass, int dim);
-
-
- public Template buildTemplate(Class> targetClass, FieldList flist) throws NoSuchFieldException {
- checkValidation(targetClass);
- return buildTemplate(targetClass, convertFieldEntries(targetClass, flist));
- }
-
- public Template buildTemplate(Class> targetClass, FieldOption implicitOption) {
- checkValidation(targetClass);
- return buildTemplate(targetClass, readFieldEntries(targetClass, implicitOption));
- }
-
- public Template buildTemplate(Class> targetClass) {
- FieldOption implicitOption = readImplicitFieldOption(targetClass);
- return buildTemplate(targetClass, implicitOption);
- }
-
- public Template buildOrdinalEnumTemplate(Class> targetClass) {
- checkOrdinalEnumValidation(targetClass);
- Enum>[] entries = (Enum>[])targetClass.getEnumConstants();
- return buildOrdinalEnumTemplate(targetClass, entries);
- }
-
- public Template buildArrayTemplate(Type arrayType) {
- Type baseType;
- Class> baseClass;
- int dim = 1;
- if(arrayType instanceof GenericArrayType) {
- GenericArrayType type = (GenericArrayType)arrayType;
- baseType = type.getGenericComponentType();
- while(baseType instanceof GenericArrayType) {
- baseType = ((GenericArrayType)baseType).getGenericComponentType();
- dim += 1;
- }
- if(baseType instanceof ParameterizedType) {
- baseClass = (Class>)((ParameterizedType)baseType).getRawType();
- } else {
- baseClass = (Class>)baseType;
- }
- } else {
- Class> type = (Class>)arrayType;
- baseClass = type.getComponentType();
- while(baseClass.isArray()) {
- baseClass = baseClass.getComponentType();
- dim += 1;
- }
- baseType = baseClass;
- }
- return buildArrayTemplate(arrayType, baseType, baseClass, dim);
- }
-
- private static Type getComponentType(Type arrayType) {
- if(arrayType instanceof GenericArrayType) {
- return ((GenericArrayType)arrayType).getGenericComponentType();
- } else {
- return ((Class>)arrayType).getComponentType();
- }
- }
-
-
- private static TemplateBuilder instance;
- static {
- instance = selectDefaultTemplateBuilder();
- }
-
- private static TemplateBuilder selectDefaultTemplateBuilder() {
- try {
- // FIXME JavassistTemplateBuilder doesn't work on DalvikVM
- if(System.getProperty("java.vm.name").equals("Dalvik")) {
- return ReflectionTemplateBuilder.getInstance();
- }
- } catch (Exception e) {
- }
- return JavassistTemplateBuilder.getInstance();
- }
-
- synchronized static void setInstance(TemplateBuilder builder) {
- instance = builder;
- }
-
- public static Template build(Class> targetClass) {
- return instance.buildTemplate(targetClass);
- }
-
- public static Template build(Class> targetClass, FieldOption implicitOption) {
- return instance.buildTemplate(targetClass, implicitOption);
- }
-
- public static Template build(Class> targetClass, FieldList flist) throws NoSuchFieldException {
- return instance.buildTemplate(targetClass, flist);
- }
-
- public static Template buildOrdinalEnum(Class> targetClass) {
- return instance.buildOrdinalEnumTemplate(targetClass);
- }
-
- public static Template buildArray(Type arrayType) {
- return instance.buildArrayTemplate(arrayType);
- }
-
-
- private static void checkValidation(Class> targetClass) {
- if(targetClass.isInterface()) {
- throw new TemplateBuildException("cannot build template of interface");
- }
- if(targetClass.isArray()) {
- throw new TemplateBuildException("cannot build template of array class");
- }
- if(targetClass.isPrimitive()) {
- throw new TemplateBuildException("cannot build template of primitive type");
- }
- }
-
- private static void checkOrdinalEnumValidation(Class> targetClass) {
- if(!targetClass.isEnum()) {
- throw new TemplateBuildException("tried to build ordinal enum template of non-enum class");
- }
- }
-
-
- static FieldEntry[] convertFieldEntries(Class> targetClass, FieldList flist) throws NoSuchFieldException {
- List src = flist.getList();
- FieldEntry[] result = new FieldEntry[src.size()];
- for(int i=0; i < src.size(); i++) {
- FieldList.Entry s = src.get(i);
- if(s.isAvailable()) {
- result[i] = new FieldEntry(targetClass.getDeclaredField(s.getName()), s.getOption());
- } else {
- result[i] = new FieldEntry();
- }
- }
- return result;
- }
-
- static FieldEntry[] readFieldEntries(Class> targetClass, FieldOption implicitOption) {
- Field[] allFields = readAllFields(targetClass);
-
- /* index:
- * @Index(0) int field_a; // 0
- * int field_b; // 1
- * @Index(3) int field_c; // 3
- * int field_d; // 4
- * @Index(2) int field_e; // 2
- * int field_f; // 5
- */
- List indexed = new ArrayList();
- int maxIndex = -1;
- for(Field f : allFields) {
- FieldOption opt = readFieldOption(f, implicitOption);
- if(opt == FieldOption.IGNORE) {
- // skip
- continue;
- }
-
- int index = readFieldIndex(f, maxIndex);
-
- if(indexed.size() > index && indexed.get(index) != null) {
- throw new TemplateBuildException("duplicated index: "+index);
- }
- if(index < 0) {
- throw new TemplateBuildException("invalid index: "+index);
- }
-
- while(indexed.size() <= index) {
- indexed.add(null);
- }
- indexed.set(index, new FieldEntry(f, opt));
-
- if(maxIndex < index) {
- maxIndex = index;
- }
- }
-
- FieldEntry[] result = new FieldEntry[maxIndex+1];
- for(int i=0; i < indexed.size(); i++) {
- FieldEntry e = indexed.get(i);
- if(e == null) {
- result[i] = new FieldEntry();
- } else {
- result[i] = e;
- }
- }
-
- return result;
- }
-
- private static Field[] readAllFields(Class> targetClass) {
- // order: [fields of super class, ..., fields of this class]
- List succ = new ArrayList();
- int total = 0;
- for(Class> c = targetClass; c != Object.class; c = c.getSuperclass()) {
- Field[] fields = c.getDeclaredFields();
- total += fields.length;
- succ.add(fields);
- }
- Field[] result = new Field[total];
- int off = 0;
- for(int i=succ.size()-1; i >= 0; i--) {
- Field[] fields = succ.get(i);
- System.arraycopy(fields, 0, result, off, fields.length);
- off += fields.length;
- }
- return result;
- }
-
- private static FieldOption readImplicitFieldOption(Class> targetClass) {
- MessagePackMessage a = targetClass.getAnnotation(MessagePackMessage.class);
- if(a == null) {
- return FieldOption.DEFAULT;
- }
- return a.value();
- }
-
- private static FieldOption readFieldOption(Field field, FieldOption implicitOption) {
- int mod = field.getModifiers();
- if(Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
- return FieldOption.IGNORE;
- }
-
- if(isAnnotated(field, Ignore.class)) {
- return FieldOption.IGNORE;
- } else if(isAnnotated(field, Required.class)) {
- return FieldOption.REQUIRED;
- } else if(isAnnotated(field, Optional.class)) {
- return FieldOption.OPTIONAL;
- } else if(isAnnotated(field, Nullable.class)) {
- if(field.getDeclaringClass().isPrimitive()) {
- return FieldOption.REQUIRED;
- } else {
- return FieldOption.NULLABLE;
- }
- }
-
- if(implicitOption != FieldOption.DEFAULT) {
- return implicitOption;
- }
-
- // default mode:
- // transient : Ignore
- // public : Required
- // others : Ignore
- if(Modifier.isTransient(mod)) {
- return FieldOption.IGNORE;
- } else if(Modifier.isPublic(mod)) {
- return FieldOption.REQUIRED;
- } else {
- return FieldOption.IGNORE;
- }
- }
-
- private static int readFieldIndex(Field field, int maxIndex) {
- Index a = field.getAnnotation(Index.class);
- if(a == null) {
- return maxIndex + 1;
- } else {
- return a.value();
- }
- }
-
- private static boolean isAnnotated(AccessibleObject ao, Class extends Annotation> with) {
- return ao.getAnnotation(with) != null;
- }
-}
-
diff --git a/java/src/main/java/org/msgpack/template/TemplateRegistry.java b/java/src/main/java/org/msgpack/template/TemplateRegistry.java
index 3f98fb46..5d869a06 100644
--- a/java/src/main/java/org/msgpack/template/TemplateRegistry.java
+++ b/java/src/main/java/org/msgpack/template/TemplateRegistry.java
@@ -1,7 +1,7 @@
//
// MessagePack for Java
//
-// Copyright (C) 2009-2010 FURUHASHI Sadayuki
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -20,48 +20,63 @@ package org.msgpack.template;
import java.util.Map;
import java.util.HashMap;
import java.lang.reflect.Type;
-import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
-import java.lang.annotation.Annotation;
-import org.msgpack.annotation.MessagePackMessage;
-import org.msgpack.annotation.MessagePackDelegate;
-import org.msgpack.annotation.MessagePackOrdinalEnum;
+import org.msgpack.template.builder.BuilderSelectorRegistry;
+import org.msgpack.template.builder.CustomTemplateBuilder;
+import org.msgpack.template.builder.TemplateBuilder;
import org.msgpack.Template;
-import org.msgpack.Templates;
public class TemplateRegistry {
private static Map map;
private static Map genericMap;
+ private static BuilderSelectorRegistry builderSelectorRegistry;
static {
map = new HashMap();
genericMap = new HashMap();
BuiltInTemplateLoader.load();
+ builderSelectorRegistry = BuilderSelectorRegistry.getInstance();
}
- public static void register(Class> target) { // auto-detect
- if(target.isEnum()) {
- register(target, TemplateBuilder.buildOrdinalEnum(target));
+ public static void register(Class> target) {
+ TemplateBuilder builder = builderSelectorRegistry.select(target);
+ if (builder != null) {
+ register(target,builder.buildTemplate(target));
} else {
- register(target, TemplateBuilder.build(target));
+ register(target,builderSelectorRegistry.getForceBuilder().buildTemplate(target));
}
}
public static void register(Class> target, FieldOption implicitOption) {
- register(target, TemplateBuilder.build(target, implicitOption));
+ TemplateBuilder builder = builderSelectorRegistry.select(target);
+ if (builder != null && builder instanceof CustomTemplateBuilder) {
+ register(target, ((CustomTemplateBuilder)builder).buildTemplate(target, implicitOption));
+ } else {
+ throw new TemplateBuildException("Cannot build template with filed option");
+ }
}
public static void register(Class> target, FieldList flist) throws NoSuchFieldException {
- register(target, TemplateBuilder.build(target, flist));
+ TemplateBuilder builder = builderSelectorRegistry.select(target);
+ if (builder != null && builder instanceof CustomTemplateBuilder) {
+ register(target, ((CustomTemplateBuilder)builder).buildTemplate(target, flist));
+ } else {
+ throw new TemplateBuildException("Cannot build template with filed list");
+ }
}
public static synchronized void register(Type rawType, Template tmpl) {
- if(rawType instanceof ParameterizedType) {
+ if (rawType instanceof ParameterizedType) {
rawType = ((ParameterizedType)rawType).getRawType();
}
map.put(rawType, tmpl);
}
+ public static boolean unregister(Class> target) {
+ Template tmpl = map.remove(target);
+ return tmpl != null;
+ }
+
public static synchronized void registerGeneric(Type rawType, GenericTemplate gtmpl) {
if(rawType instanceof ParameterizedType) {
rawType = ((ParameterizedType)rawType).getRawType();
@@ -70,22 +85,27 @@ public class TemplateRegistry {
}
public static synchronized Template lookup(Type targetType) {
- return lookupImpl(targetType, false, true);
+ return lookupImpl(targetType, true, false, true);
}
public static synchronized Template lookup(Type targetType, boolean forceBuild) {
- return lookupImpl(targetType, forceBuild, true);
+ return lookupImpl(targetType, true, forceBuild, true);
+ }
+
+ public static synchronized Template lookup(Type targetType, boolean forceLoad, boolean forceBuild) {
+ return lookupImpl(targetType, forceLoad, forceBuild, true);
}
public static synchronized Template tryLookup(Type targetType) {
- return lookupImpl(targetType, false, false);
+ return lookupImpl(targetType, true, false, false);
}
public static synchronized Template tryLookup(Type targetType, boolean forceBuild) {
- return lookupImpl(targetType, forceBuild, false);
+ return lookupImpl(targetType, true, forceBuild, false);
}
- private static synchronized Template lookupImpl(Type targetType, boolean forceBuild, boolean fallbackDefault) {
+ private static synchronized Template lookupImpl(Type targetType,
+ boolean forceLoad, boolean forceBuild, boolean fallbackDefault) {
Template tmpl;
if(targetType instanceof ParameterizedType) {
@@ -102,35 +122,26 @@ public class TemplateRegistry {
return tmpl;
}
- if(targetType instanceof GenericArrayType) {
- // GenericArrayType is not a Class>
- tmpl = TemplateBuilder.buildArray(targetType);
- register(targetType, tmpl);
- return tmpl;
+ // find match TemplateBuilder
+ TemplateBuilder builder = BuilderSelectorRegistry.getInstance().select(targetType);
+ if (builder != null) {
+ if (forceLoad) {
+ tmpl = builder.loadTemplate(targetType);
+ if (tmpl != null) {
+ register(targetType, tmpl);
+ return tmpl;
+ }
+ }
+
+ tmpl = builder.buildTemplate(targetType);
+ if (tmpl != null) {
+ register(targetType, tmpl);
+ return tmpl;
+ }
}
Class> target = (Class>)targetType;
- if(target.isArray()) {
- // FIXME can't distinguish type-erased T<>[]?
- tmpl = TemplateBuilder.buildArray(target);
- register(target, tmpl);
- return tmpl;
- }
-
- if(isAnnotated(target, MessagePackMessage.class)) {
- tmpl = TemplateBuilder.build(target);
- register(target, tmpl);
- return tmpl;
- } else if(isAnnotated(target, MessagePackDelegate.class)) {
- // TODO DelegateTemplate
- throw new UnsupportedOperationException("not supported yet. : " + target.getName());
- } else if(isAnnotated(target, MessagePackOrdinalEnum.class)) {
- tmpl = TemplateBuilder.buildOrdinalEnum(target);
- register(target, tmpl);
- return tmpl;
- }
-
for(Class> i : target.getInterfaces()) {
tmpl = map.get(i);
if(tmpl != null) {
@@ -150,7 +161,7 @@ public class TemplateRegistry {
}
if(forceBuild) {
- tmpl = TemplateBuilder.build(target);
+ tmpl = builderSelectorRegistry.getForceBuilder().buildTemplate(target);
register(target, tmpl);
return tmpl;
}
@@ -174,7 +185,7 @@ public class TemplateRegistry {
}
return new DefaultTemplate((Class>)parameterizedType.getRawType(), parameterizedType);
} else {
- throw new IllegalArgumentException("actual types of the generic type are erased: "+targetType);
+ throw new IllegalArgumentException("Actual types of the generic type are erased: "+targetType);
}
}
@@ -193,13 +204,5 @@ public class TemplateRegistry {
return gtmpl.build(tmpls);
}
-
- private static boolean isAnnotated(Class> ao, Class extends Annotation> with) {
- return ao.getAnnotation(with) != null;
- }
-
- public static void setTemplateBuilder(TemplateBuilder builder) {
- TemplateBuilder.setInstance(builder);
- }
}
diff --git a/java/src/main/java/org/msgpack/template/builder/AnnotationTemplateBuilderSelector.java b/java/src/main/java/org/msgpack/template/builder/AnnotationTemplateBuilderSelector.java
new file mode 100644
index 00000000..10bf5e62
--- /dev/null
+++ b/java/src/main/java/org/msgpack/template/builder/AnnotationTemplateBuilderSelector.java
@@ -0,0 +1,54 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
+//
+// 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.
+//
+package org.msgpack.template.builder;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import org.msgpack.annotation.MessagePackMessage;
+
+public class AnnotationTemplateBuilderSelector implements BuilderSelector{
+
+ public static final String NAME = "AnnotationTemplateBuilder";
+
+ TemplateBuilder builder;
+
+ public AnnotationTemplateBuilderSelector(TemplateBuilder builder){
+ this.builder = builder;
+ }
+
+ @Override
+ public String getName(){
+ return NAME;
+ }
+
+ @Override
+ public boolean matchType(Type targetType) {
+ Class> targetClass = (Class>)targetType;
+ return isAnnotated(targetClass, MessagePackMessage.class);
+ }
+
+ @Override
+ public TemplateBuilder getTemplateBuilder(Type targetType) {
+ return builder;
+ }
+
+ public static boolean isAnnotated(Class> targetClass, Class extends Annotation> with) {
+ return targetClass.getAnnotation(with) != null;
+ }
+}
diff --git a/java/src/main/java/org/msgpack/template/builder/ArrayTemplateBuilder.java b/java/src/main/java/org/msgpack/template/builder/ArrayTemplateBuilder.java
new file mode 100644
index 00000000..24e277ac
--- /dev/null
+++ b/java/src/main/java/org/msgpack/template/builder/ArrayTemplateBuilder.java
@@ -0,0 +1,194 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
+//
+// 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.
+//
+package org.msgpack.template.builder;
+
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+import org.msgpack.AbstractTemplate;
+import org.msgpack.MessagePackObject;
+import org.msgpack.MessageTypeException;
+import org.msgpack.Packer;
+import org.msgpack.Template;
+import org.msgpack.Unpacker;
+import org.msgpack.template.BooleanArrayTemplate;
+import org.msgpack.template.DoubleArrayTemplate;
+import org.msgpack.template.FloatArrayTemplate;
+import org.msgpack.template.IntArrayTemplate;
+import org.msgpack.template.LongArrayTemplate;
+import org.msgpack.template.ShortArrayTemplate;
+import org.msgpack.template.TemplateRegistry;
+
+public class ArrayTemplateBuilder implements TemplateBuilder {
+
+ static class ReflectionObjectArrayTemplate extends AbstractTemplate {
+ private Class> componentClass;
+ private Template elementTemplate;
+
+ public ReflectionObjectArrayTemplate(Class> componentClass, Template elementTemplate) {
+ this.componentClass = componentClass;
+ this.elementTemplate = elementTemplate;
+ }
+
+ public void pack(Packer pk, Object target) throws IOException {
+ if(!(target instanceof Object[]) || !componentClass.isAssignableFrom(target.getClass().getComponentType())) {
+ throw new MessageTypeException();
+ }
+ Object[] array = (Object[])target;
+ int length = array.length;
+ pk.packArray(length);
+ for(int i=0; i < length; i++) {
+ elementTemplate.pack(pk, array[i]);
+ }
+ }
+
+ public Object unpack(Unpacker pac, Object to) throws IOException {
+ int length = pac.unpackArray();
+ Object[] array = (Object[])Array.newInstance(componentClass, length);
+ for(int i=0; i < length; i++) {
+ array[i] = elementTemplate.unpack(pac, null);
+ }
+ return array;
+ }
+
+ public Object convert(MessagePackObject from, Object to) throws MessageTypeException {
+ MessagePackObject[] src = from.asArray();
+ int length = src.length;
+ Object[] array = (Object[])Array.newInstance(componentClass, length);
+ for(int i=0; i < length; i++) {
+ array[i] = elementTemplate.convert(src[i], null);
+ }
+ return array;
+ }
+ }
+
+ static class ReflectionMultidimentionalArrayTemplate extends AbstractTemplate {
+ private Class> componentClass;
+ private Template componentTemplate;
+
+ public ReflectionMultidimentionalArrayTemplate(Class> componentClass, Template componentTemplate) {
+ this.componentClass = componentClass;
+ this.componentTemplate = componentTemplate;
+ }
+
+ Class> getComponentClass() {
+ return componentClass;
+ }
+
+ public void pack(Packer pk, Object target) throws IOException {
+ Object[] array = (Object[])target;
+ int length = array.length;
+ pk.packArray(length);
+ for(int i=0; i < length; i++) {
+ componentTemplate.pack(pk, array[i]);
+ }
+ }
+
+ public Object unpack(Unpacker pac, Object to) throws IOException, MessageTypeException {
+ int length = pac.unpackArray();
+ Object[] array = (Object[])Array.newInstance(componentClass, length);
+ for(int i=0; i < length; i++) {
+ array[i] = componentTemplate.unpack(pac, null);
+ }
+ return array;
+ }
+
+ public Object convert(MessagePackObject from, Object to) throws MessageTypeException {
+ MessagePackObject[] src = from.asArray();
+ int length = src.length;
+ Object[] array = (Object[])Array.newInstance(componentClass, length);
+ for(int i=0; i < length; i++) {
+ array[i] = componentTemplate.convert(src[i], null);
+ }
+ return array;
+ }
+ }
+
+ @Override
+ public Template buildTemplate(Type arrayType) {
+ Type baseType;
+ Class> baseClass;
+ int dim = 1;
+ if(arrayType instanceof GenericArrayType) {
+ GenericArrayType type = (GenericArrayType)arrayType;
+ baseType = type.getGenericComponentType();
+ while(baseType instanceof GenericArrayType) {
+ baseType = ((GenericArrayType)baseType).getGenericComponentType();
+ dim += 1;
+ }
+ if(baseType instanceof ParameterizedType) {
+ baseClass = (Class>)((ParameterizedType)baseType).getRawType();
+ } else {
+ baseClass = (Class>)baseType;
+ }
+ } else {
+ Class> type = (Class>)arrayType;
+ baseClass = type.getComponentType();
+ while(baseClass.isArray()) {
+ baseClass = baseClass.getComponentType();
+ dim += 1;
+ }
+ baseType = baseClass;
+ }
+ return toTemplate(arrayType, baseType, baseClass, dim);
+
+ }
+
+ private Template toTemplate(Type arrayType, Type genericBaseType, Class> baseClass, int dim) {
+ if(dim == 1) {
+ if(baseClass == boolean.class) {
+ return BooleanArrayTemplate.getInstance();
+ } else if(baseClass == short.class) {
+ return ShortArrayTemplate.getInstance();
+ } else if(baseClass == int.class) {
+ return IntArrayTemplate.getInstance();
+ } else if(baseClass == long.class) {
+ return LongArrayTemplate.getInstance();
+ } else if(baseClass == float.class) {
+ return FloatArrayTemplate.getInstance();
+ } else if(baseClass == double.class) {
+ return DoubleArrayTemplate.getInstance();
+ } else {
+ Template baseTemplate = TemplateRegistry.lookup(genericBaseType);
+ return new ReflectionObjectArrayTemplate(baseClass, baseTemplate);
+ }
+ } else if(dim == 2) {
+ Class> componentClass = Array.newInstance(baseClass, 0).getClass();
+ Template componentTemplate = toTemplate(arrayType, genericBaseType, baseClass, dim-1);
+ return new ReflectionMultidimentionalArrayTemplate(componentClass, componentTemplate);
+ } else {
+ ReflectionMultidimentionalArrayTemplate componentTemplate = (ReflectionMultidimentionalArrayTemplate)
+ toTemplate(arrayType, genericBaseType, baseClass, dim-1);
+ Class> componentClass = Array.newInstance(componentTemplate.getComponentClass(), 0).getClass();
+ return new ReflectionMultidimentionalArrayTemplate(componentClass, componentTemplate);
+ }
+ }
+
+ @Override
+ public void writeTemplate(Type targetType, String directoryName) {
+ throw new UnsupportedOperationException(targetType.toString());
+ }
+
+ @Override
+ public Template loadTemplate(Type targetType) {
+ return null;
+ }
+}
diff --git a/java/src/main/java/org/msgpack/template/builder/ArrayTemplateBuilderSelector.java b/java/src/main/java/org/msgpack/template/builder/ArrayTemplateBuilderSelector.java
new file mode 100644
index 00000000..eeefd7ec
--- /dev/null
+++ b/java/src/main/java/org/msgpack/template/builder/ArrayTemplateBuilderSelector.java
@@ -0,0 +1,49 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
+//
+// 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.
+//
+package org.msgpack.template.builder;
+
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Type;
+
+public class ArrayTemplateBuilderSelector implements BuilderSelector {
+
+ public static final String NAME = "ArrayTemplateBuilder";
+
+ ArrayTemplateBuilder templateBuilder = new ArrayTemplateBuilder();
+
+ @Override
+ public String getName(){
+ return NAME;
+ }
+
+ @Override
+ public boolean matchType(Type targetType) {
+ if(targetType instanceof GenericArrayType){
+ return true;
+ }
+ Class> targetClass = (Class>)targetType;
+ return targetClass.isArray();
+ }
+
+ @Override
+ public TemplateBuilder getTemplateBuilder(Type target) {
+ return templateBuilder;
+ }
+
+
+}
diff --git a/java/src/main/java/org/msgpack/template/builder/BeansBuildContext.java b/java/src/main/java/org/msgpack/template/builder/BeansBuildContext.java
new file mode 100644
index 00000000..af88d3ff
--- /dev/null
+++ b/java/src/main/java/org/msgpack/template/builder/BeansBuildContext.java
@@ -0,0 +1,285 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
+//
+// 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.
+//
+package org.msgpack.template.builder;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+import org.msgpack.*;
+import org.msgpack.template.*;
+
+import javassist.CannotCompileException;
+import javassist.CtClass;
+import javassist.CtConstructor;
+import javassist.CtNewConstructor;
+import javassist.NotFoundException;
+
+public class BeansBuildContext extends BuildContextBase {
+ protected BeansFieldEntry[] entries;
+ protected Class> origClass;
+ protected String origName;
+ protected Template[] templates;
+ protected int minimumArrayLength;
+
+ public BeansBuildContext(JavassistTemplateBuilder director) {
+ super(director);
+ }
+
+ public Template buildTemplate(Class> targetClass, BeansFieldEntry[] entries, Template[] templates) {
+ this.entries = entries;
+ this.templates = templates;
+ this.origClass = targetClass;
+ this.origName = this.origClass.getName();
+ return build(this.origName);
+ }
+
+ protected void setSuperClass() throws CannotCompileException, NotFoundException {
+ this.tmplCtClass.setSuperclass(
+ director.getCtClass(JavassistTemplateBuilder.JavassistTemplate.class.getName()));
+ }
+
+ protected void buildConstructor() throws CannotCompileException, NotFoundException {
+ // Constructor(Class targetClass, Template[] templates)
+ CtConstructor newCtCons = CtNewConstructor.make(
+ new CtClass[] {
+ director.getCtClass(Class.class.getName()),
+ director.getCtClass(Template.class.getName()+"[]")
+ },
+ new CtClass[0],
+ this.tmplCtClass);
+ this.tmplCtClass.addConstructor(newCtCons);
+ }
+
+ protected Template buildInstance(Class> c) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
+ Constructor> cons = c.getConstructor(new Class[] {
+ Class.class,
+ Template[].class
+ });
+ Object tmpl = cons.newInstance(new Object[] {
+ this.origClass,
+ this.templates
+ });
+ return (Template)tmpl;
+ }
+
+ protected void buildMethodInit() {
+ this.minimumArrayLength = 0;
+ for(int i=0; i < entries.length; i++) {
+ IFieldEntry e = entries[i];
+ if(e.isRequired() || e.isNullable()) {
+ this.minimumArrayLength = i+1;
+ }
+ }
+ }
+
+ protected String buildPackMethodBody() {
+ resetStringBuilder();
+ buildString("{");
+ buildString("%s _$$_t = (%s)$2;", this.origName, this.origName);
+ buildString("$1.packArray(%d);", entries.length);
+ for(int i=0; i < entries.length; i++) {
+ BeansFieldEntry e = entries[i];
+ if(!e.isAvailable()) {
+ buildString("$1.packNil();");
+ continue;
+ }
+ Class> type = e.getType();
+ if(type.isPrimitive()) {
+ buildString("$1.%s(_$$_t.%s());", primitivePackName(type), e.getGetterName());
+ } else {
+ buildString("if(_$$_t.%s() == null) {", e.getGetterName());
+ if(!e.isNullable() && !e.isOptional()) {
+ buildString("throw new %s();", MessageTypeException.class.getName());
+ } else {
+ buildString("$1.packNil();");
+ }
+ buildString("} else {");
+ buildString(" this.templates[%d].pack($1, _$$_t.%s());", i, e.getGetterName());
+ buildString("}");
+ }
+ }
+ buildString("}");
+ return getBuiltString();
+ }
+
+ protected String buildUnpackMethodBody() {
+ resetStringBuilder();
+ buildString("{ ");
+
+ buildString("%s _$$_t;", this.origName);
+ buildString("if($2 == null) {");
+ buildString(" _$$_t = new %s();", this.origName);
+ buildString("} else {");
+ buildString(" _$$_t = (%s)$2;", this.origName);
+ buildString("}");
+
+ buildString("int length = $1.unpackArray();");
+ buildString("if(length < %d) {", this.minimumArrayLength);
+ buildString(" throw new %s();", MessageTypeException.class.getName());
+ buildString("}");
+
+ int i;
+ for(i=0; i < this.minimumArrayLength; i++) {
+ BeansFieldEntry e = entries[i];
+ if(!e.isAvailable()) {
+ buildString("$1.unpackObject();");
+ continue;
+ }
+
+ buildString("if($1.tryUnpackNull()) {");
+ if(e.isRequired()) {
+ // Required + nil => exception
+ buildString("throw new %s();", MessageTypeException.class.getName());
+ } else if(e.isOptional()) {
+ // Optional + nil => keep default value
+ } else { // Nullable
+ // Nullable + nil => set null
+ buildString("_$$_t.%s(null);", e.getSetterName());
+ }
+ buildString("} else {");
+ Class> type = e.getType();
+ if(type.isPrimitive()) {
+ buildString("_$$_t.set%s( $1.%s() );", e.getName(), primitiveUnpackName(type));
+ } else {
+ buildString("_$$_t.set%s( (%s)this.templates[%d].unpack($1, _$$_t.get%s()) );", e.getName(), e.getJavaTypeName(), i, e.getName());
+ }
+ buildString("}");
+ }
+
+ for(; i < entries.length; i++) {
+ buildString("if(length <= %d) { return _$$_t; }", i);
+
+ BeansFieldEntry e = entries[i];
+ if(!e.isAvailable()) {
+ buildString("$1.unpackObject();");
+ continue;
+ }
+
+ buildString("if($1.tryUnpackNull()) {");
+ // this is Optional field becaue i >= minimumArrayLength
+ // Optional + nil => keep default value
+ buildString("} else {");
+ Class> type = e.getType();
+ if(type.isPrimitive()) {
+ buildString("_$$_t.%s( $1.%s() );", e.getSetterName(), primitiveUnpackName(type));
+ } else {
+ buildString("_$$_t.%s( (%s)this.templates[%d].unpack($1, _$$_t.%s()) );", e.getSetterName(), e.getJavaTypeName(), i, e.getGetterName());
+ }
+ buildString("}");
+ }
+
+ // latter entries are all Optional + nil => keep default value
+
+ buildString("for(int i=%d; i < length; i++) {", i);
+ buildString(" $1.unpackObject();");
+ buildString("}");
+
+ buildString("return _$$_t;");
+
+ buildString("}");
+ return getBuiltString();
+ }
+
+ protected String buildConvertMethodBody() {
+ resetStringBuilder();
+ buildString("{ ");
+
+ buildString("%s _$$_t;", this.origName);
+ buildString("if($2 == null) {");
+ buildString(" _$$_t = new %s();", this.origName);
+ buildString("} else {");
+ buildString(" _$$_t = (%s)$2;", this.origName);
+ buildString("}");
+
+ buildString("%s[] array = $1.asArray();", MessagePackObject.class.getName());
+ buildString("int length = array.length;");
+ buildString("if(length < %d) {", this.minimumArrayLength);
+ buildString(" throw new %s();", MessageTypeException.class.getName());
+ buildString("}");
+
+ buildString("%s obj;", MessagePackObject.class.getName());
+
+ int i;
+ for(i=0; i < this.minimumArrayLength; i++) {
+ BeansFieldEntry e = entries[i];
+ if(!e.isAvailable()) {
+ continue;
+ }
+
+ buildString("obj = array[%d];", i);
+ buildString("if(obj.isNil()) {");
+ if(e.isRequired()) {
+ // Required + nil => exception
+ buildString("throw new %s();", MessageTypeException.class.getName());
+ } else if(e.isOptional()) {
+ // Optional + nil => keep default value
+ } else { // Nullable
+ // Nullable + nil => set null
+ buildString("_$$_t.%s( null );", e.getSetterName());
+ }
+ buildString("} else {");
+ Class> type = e.getType();
+ if(type.isPrimitive()) {
+ buildString("_$$_t.%s( obj.%s() );", e.getSetterName(), primitiveConvertName(type));
+ } else {
+ buildString("_$$_t.%s( (%s)this.templates[%d].convert(obj, _$$_t.%s()) );", e.getSetterName(), e.getJavaTypeName(), i, e.getGetterName());
+ }
+ buildString("}");
+ }
+
+ for(; i < entries.length; i++) {
+ buildString("if(length <= %d) { return _$$_t; }", i);
+
+ BeansFieldEntry e = entries[i];
+ if(!e.isAvailable()) {
+ continue;
+ }
+
+ buildString("obj = array[%d];", i);
+ buildString("if(obj.isNil()) {");
+ // this is Optional field becaue i >= minimumArrayLength
+ // Optional + nil => keep default value
+ buildString("} else {");
+ Class> type = e.getType();
+ if(type.isPrimitive()) {
+ buildString("_$$_t.%s( obj.%s() );", e.getSetterName(), primitiveConvertName(type));
+ } else {
+ buildString("_$$_t.%s( (%s)this.templates[%d].convert(obj, _$$_t.%s()) );", e.getSetterName(), e.getJavaTypeName(), i, e.getGetterName());
+ }
+ buildString("}");
+ }
+
+ // latter entries are all Optional + nil => keep default value
+
+ buildString("return _$$_t;");
+
+ buildString("}");
+ return getBuiltString();
+ }
+
+ @Override
+ public void writeTemplate(Class> targetClass, BeansFieldEntry[] entries,
+ Template[] templates, String directoryName) {
+ throw new UnsupportedOperationException(targetClass.getName());
+ }
+
+ @Override
+ public Template loadTemplate(Class> targetClass, BeansFieldEntry[] entries, Template[] templates) {
+ throw new UnsupportedOperationException(targetClass.getName());
+ }
+}
\ No newline at end of file
diff --git a/java/src/main/java/org/msgpack/template/builder/BeansTemplateBuilder.java b/java/src/main/java/org/msgpack/template/builder/BeansTemplateBuilder.java
new file mode 100644
index 00000000..57634660
--- /dev/null
+++ b/java/src/main/java/org/msgpack/template/builder/BeansTemplateBuilder.java
@@ -0,0 +1,328 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
+//
+// 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.
+//
+package org.msgpack.template.builder;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+
+import org.msgpack.AbstractTemplate;
+import org.msgpack.MessagePackObject;
+import org.msgpack.MessageTypeException;
+import org.msgpack.Packer;
+import org.msgpack.Template;
+import org.msgpack.Unpacker;
+import org.msgpack.template.BeansFieldEntry;
+import org.msgpack.template.BeansFieldEntryReader;
+import org.msgpack.template.IFieldEntry;
+import org.msgpack.template.IFieldEntryReader;
+import org.msgpack.template.TemplateRegistry;
+
+/**
+ * Class for building java reflection template builder for java beans class.
+ * @author takeshita
+ *
+ */
+public class BeansTemplateBuilder extends CustomTemplateBuilder{
+
+ IFieldEntryReader reader = new BeansFieldEntryReader();
+
+ public BeansTemplateBuilder(){}
+
+ @Override
+ public IFieldEntryReader getFieldEntryReader(){
+ return reader;
+ }
+
+ static class ReflectionEntry{
+ BeansFieldEntry entry;
+ public ReflectionEntry(BeansFieldEntry entry){
+ this.entry = entry;
+ }
+
+ public void pack(Object value , Packer packer) throws IOException{
+ packer.pack(value);
+ }
+ public void convert(Object target, MessagePackObject obj) throws MessageTypeException, IllegalAccessException {
+ entry.set(target, obj.convert(entry.getType()));
+ }
+
+ public void unpack(Object target, Unpacker unpacker) throws IOException, MessageTypeException, IllegalAccessException {
+ entry.set(target, unpacker.unpack(entry.getType()));
+ }
+
+ public void setNull(Object target){
+ entry.set(target, null);
+ }
+
+ public boolean isRequired(){
+ return entry.isRequired();
+ }
+ public boolean isNullable(){
+ return entry.isNullable();
+ }
+ public boolean isAvailable(){
+ return entry.isAvailable();
+ }
+ public boolean isOptional(){
+ return entry.isOptional();
+ }
+ public Object get(Object target){
+ return entry.get(target);
+ }
+
+ }
+
+ static class ObjectFieldEntry extends ReflectionEntry{
+ Template template;
+ public ObjectFieldEntry(BeansFieldEntry entry,Template template){
+ super(entry);
+ this.template = template;
+ }
+ public void pack(Object value , Packer packer) throws IOException{
+ template.pack(packer,value);
+ }
+ public void convert(Object target, MessagePackObject obj) throws MessageTypeException, IllegalAccessException {
+ Class