Merge pull request #102 from aliiohs/feature/FixDateNilBug
Fix: date nil bug
diff --git a/codec.go b/codec.go
index 6c91ce5..184938c 100644
--- a/codec.go
+++ b/codec.go
@@ -292,6 +292,14 @@
return
}
}
+ //temporary process, only handle the same type of situation
+ if v.IsValid() && UnpackPtrType(dest.Type()) == UnpackPtrType(v.Type()) && dest.Kind() == reflect.Ptr && dest.CanSet() {
+ for dest.Type() != v.Type() {
+ v = PackPtr(v)
+ }
+ dest.Set(v)
+ return
+ }
// if the kind of dest is Ptr, the original value will be zero value
// set value on zero value is not allowed
@@ -307,7 +315,6 @@
for v.IsValid() && v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Ptr {
v = v.Elem()
}
-
// zero value not need to set
if !v.IsValid() {
return
@@ -320,7 +327,6 @@
} else {
v = UnpackPtrValue(v)
}
-
// zero value not need to set
if !v.IsValid() {
return
diff --git a/date.go b/date.go
index 8ae4cc6..50723e0 100644
--- a/date.go
+++ b/date.go
@@ -15,6 +15,7 @@
package hessian
import (
+ "reflect"
"time"
)
@@ -26,12 +27,21 @@
// Date
/////////////////////////////////////////
+var ZeroDate = time.Time{}
+
// # time in UTC encoded as 64-bit long milliseconds since epoch
// ::= x4a b7 b6 b5 b4 b3 b2 b1 b0
// ::= x4b b3 b2 b1 b0 # minutes since epoch
-func encDateInMs(b []byte, v time.Time) []byte {
+func encDateInMs(b []byte, i interface{}) []byte {
+
+ value := UnpackPtrValue(reflect.ValueOf(i))
+ vi := value.Interface().(time.Time)
+ if vi == ZeroDate {
+ b = append(b, BC_NULL)
+ return nil
+ }
b = append(b, BC_DATE)
- return append(b, PackInt64(v.UnixNano()/1e6)...)
+ return append(b, PackInt64(vi.UnixNano()/1e6)...)
}
func encDateInMimute(b []byte, v time.Time) []byte {
@@ -64,6 +74,8 @@
}
switch {
+ case tag == BC_NULL:
+ return ZeroDate, nil
case tag == BC_DATE: //'d': //date
s = buf[:8]
l, err = d.next(s)
diff --git a/date_test.go b/date_test.go
index 02cc93b..9044002 100644
--- a/date_test.go
+++ b/date_test.go
@@ -18,6 +18,27 @@
"testing"
"time"
)
+import (
+ "github.com/stretchr/testify/assert"
+)
+
+func init() {
+ RegisterPOJO(&DateDemo{})
+}
+
+type DateDemo struct {
+ Name string
+ Date time.Time
+ Dates []**time.Time
+ NilDate *time.Time
+ Date1 *time.Time
+ Date2 **time.Time
+ Date3 ***time.Time
+}
+
+func (DateDemo) JavaClassName() string {
+ return "test.model.DateDemo"
+}
func TestEncDate(t *testing.T) {
var (
@@ -71,3 +92,64 @@
testJavaDecode(t, "argDate_1", time.Date(1998, 5, 8, 9, 51, 31, 0, time.UTC))
testJavaDecode(t, "argDate_2", time.Date(1998, 5, 8, 9, 51, 0, 0, time.UTC))
}
+
+func TestEncDateNull(t *testing.T) {
+ var (
+ v string
+ tz time.Time
+ e *Encoder
+ d *Decoder
+ res interface{}
+ )
+ v = "2014-02-09 06:15:23 +0800 CST"
+ tz, _ = time.Parse("2006-01-02 15:04:05 +0800 CST", v)
+ d1 := &tz
+ d2 := &d1
+ d3 := &d2
+
+ date := DateDemo{
+ Name: "zs",
+ Date: ZeroDate,
+ Dates: []**time.Time{d2, d2},
+ NilDate: nil,
+ Date1: nil,
+ Date2: d2,
+ Date3: d3,
+ }
+ e = NewEncoder()
+ e.Encode(date)
+ if len(e.Buffer()) == 0 {
+ t.Fail()
+ }
+ d = NewDecoder(e.Buffer())
+ res, _ = d.Decode()
+ assert.Equal(t, ZeroDate, res.(*DateDemo).Date)
+ assert.Equal(t, 2, len(res.(*DateDemo).Dates))
+ assert.Equal(t, tz.Local().String(), (*res.(*DateDemo).Dates[0]).String())
+ assert.Equal(t, &ZeroDate, res.(*DateDemo).NilDate)
+ assert.Equal(t, ZeroDate, *res.(*DateDemo).Date1)
+ assert.Equal(t, tz.Local().String(), (*res.(*DateDemo).Date2).String())
+ assert.Equal(t, tz.Local().String(), (*(*res.(*DateDemo).Date3)).String())
+
+}
+
+func TestDateNulJavaDecode(t *testing.T) {
+ date := DateDemo{
+ Name: "zs",
+ Date: ZeroDate,
+ }
+ testJavaDecode(t, "customArgTypedFixedList_DateNull", date)
+}
+
+func TestDateNilDecode(t *testing.T) {
+
+ doTestDateNull(t, "customReplyTypedFixedDateNull")
+}
+
+func doTestDateNull(t *testing.T, method string) {
+ testDecodeFrameworkFunc(t, method, func(r interface{}) {
+ t.Logf("%#v", r)
+ assert.Equal(t, ZeroDate, r.(*DateDemo).Date)
+ assert.Equal(t, &ZeroDate, r.(*DateDemo).Date1)
+ })
+}
diff --git a/encode.go b/encode.go
index f5f333b..7ae4d05 100644
--- a/encode.go
+++ b/encode.go
@@ -101,8 +101,12 @@
e.buffer = encInt64(e.buffer, int64(val))
case time.Time:
- e.buffer = encDateInMs(e.buffer, val)
- // e.buffer = encDateInMimute(v.(time.Time), e.buffer)
+ if ZeroDate == val {
+ e.buffer = encNull(e.buffer)
+ } else {
+ e.buffer = encDateInMs(e.buffer, &val)
+ // e.buffer = encDateInMimute(v.(time.Time), e.buffer)
+ }
case float32:
e.buffer = encFloat(e.buffer, float64(val))
@@ -123,15 +127,21 @@
t := UnpackPtrType(reflect.TypeOf(v))
switch t.Kind() {
case reflect.Struct:
+ vv := reflect.ValueOf(v)
+ vv = UnpackPtr(vv)
+ if !vv.IsValid() {
+ e.buffer = encNull(e.buffer)
+ return nil
+ }
+ if vv.Type().String() == "time.Time" {
+ e.buffer = encDateInMs(e.buffer, v)
+ return nil
+ }
if p, ok := v.(POJO); ok {
var clazz string
- vv := reflect.ValueOf(v)
- vv = UnpackPtr(vv)
- if vv.IsValid() {
- clazz = p.JavaClassName()
- if c, ok := GetSerializer(clazz); ok {
- return c.EncObject(e, p)
- }
+ clazz = p.JavaClassName()
+ if c, ok := GetSerializer(clazz); ok {
+ return c.EncObject(e, p)
}
return e.encObject(p)
}
diff --git a/object.go b/object.go
index d9f3cc0..39b7385 100644
--- a/object.go
+++ b/object.go
@@ -424,12 +424,13 @@
err error
s interface{}
)
- if fldRawValue.Type().String() == "time.Time" {
+ typ := UnpackPtrType(fldRawValue.Type())
+ if typ.String() == "time.Time" {
s, err = d.decDate(TAG_READ)
if err != nil {
return nil, perrors.WithStack(err)
}
- fldRawValue.Set(reflect.ValueOf(s))
+ SetValue(fldRawValue, EnsurePackValue(s))
} else {
s, err = d.decObject(TAG_READ)
if err != nil {
diff --git a/test_hessian/src/main/java/test/TestCustomDecode.java b/test_hessian/src/main/java/test/TestCustomDecode.java
index 27ac4ce..5eae85f 100644
--- a/test_hessian/src/main/java/test/TestCustomDecode.java
+++ b/test_hessian/src/main/java/test/TestCustomDecode.java
@@ -26,6 +26,7 @@
import java.util.Date;
import java.util.List;
import java.math.BigDecimal;
+import test.model.DateDemo;
public class TestCustomDecode {
@@ -168,4 +169,9 @@
BigDecimal o = (BigDecimal) input.readObject();
return o.toString().equals( "100.256");
}
+
+ public Object customArgTypedFixedList_DateNull() throws Exception {
+ DateDemo o = (DateDemo) input.readObject();
+ return o.getDate() == null && o.getDate1() == null;
+ }
}
\ No newline at end of file
diff --git a/test_hessian/src/main/java/test/TestCustomReply.java b/test_hessian/src/main/java/test/TestCustomReply.java
index 21ada2a..bbe6403 100644
--- a/test_hessian/src/main/java/test/TestCustomReply.java
+++ b/test_hessian/src/main/java/test/TestCustomReply.java
@@ -23,6 +23,7 @@
import java.util.Date;
import java.util.HashMap;
import java.math.BigDecimal;
+import test.model.DateDemo;
public class TestCustomReply {
@@ -346,6 +347,12 @@
output.flush();
}
+ public void customReplyTypedFixedDateNull() throws Exception {
+ DateDemo demo = new DateDemo("zhangshan",null,null);
+ output.writeObject(demo);
+ output.flush();
+ }
+
}
class TypedListTest implements Serializable {
diff --git a/test_hessian/src/main/java/test/model/DateDemo.java b/test_hessian/src/main/java/test/model/DateDemo.java
new file mode 100644
index 0000000..69a78fb
--- /dev/null
+++ b/test_hessian/src/main/java/test/model/DateDemo.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 test.model;
+
+import java.io.Serializable;
+import java.util.Date;
+
+public class DateDemo implements Serializable {
+ private String name;
+ private Date date;
+ private Date date1;
+
+ public String getName() {
+ return name;
+ }
+
+ public DateDemo() {}
+
+ public DateDemo(String name,Date date,Date date1) {
+ this.name = name;
+ this.date = date;
+ this.date1 = date1;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+ public Date getDate() {
+ return date;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+ public Date getDate1() {
+ return date1;
+ }
+
+ public void setDate1(Date date1) {
+ this.date1 = date1;
+ }
+
+}
\ No newline at end of file