Fix hessian2 serialized short, byte is converted to int bug(#20)

fixes #19
diff --git a/pom.xml b/pom.xml
index cbee5eb..208810e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
     <groupId>com.alibaba</groupId>
     <artifactId>hessian-lite</artifactId>
     <packaging>jar</packaging>
-    <version>3.2.5-SNAPSHOT</version>
+    <version>3.2.7-SNAPSHOT</version>
     <name>Hessian Lite(Alibaba embed version)</name>
 
     <properties>
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianInput.java b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianInput.java
index 1d63fec..db0e574 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianInput.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianInput.java
@@ -100,6 +100,8 @@
     public void setSerializerFactory(SerializerFactory ser) {
     }
 
+    public abstract boolean checkAndReadNull();
+
     /**
      * Reads the call
      * <p>
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BasicDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/BasicDeserializer.java
index 20c593f..dc631e5 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BasicDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/BasicDeserializer.java
@@ -148,6 +148,9 @@
     @Override
     public Object readObject(AbstractHessianInput in)
             throws IOException {
+        if (in.checkAndReadNull()) {
+            return null;
+        }
         switch (_code) {
             case NULL:
                 // hessian/3490
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/CollectionDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/CollectionDeserializer.java
index 827f7a3..fb23606 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/CollectionDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/CollectionDeserializer.java
@@ -92,7 +92,7 @@
         }
 
         while (!in.isEnd()) {
-            deserializerList(in, deserializer, list);
+            list.add(deserializer != null ? deserializer.readObject(in) : in.readObject());
         }
 
 
@@ -121,23 +121,13 @@
         }
 
         for (; length > 0; length--) {
-            deserializerList(in, deserializer, list);
+            list.add(deserializer != null ? deserializer.readObject(in) : in.readObject());
         }
 
 
         return list;
     }
 
-    private void deserializerList(AbstractHessianInput in, Deserializer deserializer, Collection list) throws IOException {
-        Hessian2Input._isNull = false;
-        Object object = deserializer != null ? deserializer.readObject(in) : in.readObject();
-        if (Hessian2Input._isNull) {
-            list.add(null);
-        } else {
-            list.add(object);
-        }
-    }
-
     private Collection createList()
             throws IOException {
         Collection list = null;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Input.java b/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Input.java
index 3d1f731..f241d63 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Input.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Input.java
@@ -90,7 +90,6 @@
     private static final int GAP = 16;
     private static Field _detailMessageField;
     private static boolean _isCloseStreamOnClose;
-    public static boolean _isNull = false;
 
     static {
         try {
@@ -185,6 +184,19 @@
         return _replyFault;
     }
 
+    @Override
+    public boolean checkAndReadNull() {
+        try {
+            int tag = read();
+            if ('N' == tag) {
+                return true;
+            }
+            _offset--;
+        } catch (IOException ignored) {
+        }
+        return false;
+    }
+
     /**
      * Starts reading the call
      * <p>
@@ -752,12 +764,10 @@
     public final int readInt()
             throws IOException {
         //int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
-        _isNull = false;
         int tag = read();
 
         switch (tag) {
             case 'N':
-                _isNull = true;
                 return 0;
 
             case 'F':
@@ -973,12 +983,10 @@
     @Override
     public long readLong()
             throws IOException {
-        _isNull = false;
         int tag = read();
 
         switch (tag) {
             case 'N':
-                _isNull = true;
                 return 0;
 
             case 'F':
@@ -1203,12 +1211,10 @@
     @Override
     public double readDouble()
             throws IOException {
-        _isNull = false;
         int tag = read();
 
         switch (tag) {
             case 'N':
-                _isNull = true;
                 return 0;
 
             case 'F':
@@ -3360,8 +3366,9 @@
             case 'N':
                 return null;
 
-            case 'B':
-            case 'b':
+            case BC_BINARY:
+            case BC_BINARY_CHUNK:
+            case 'b': //maybe it's a mistype of BC_BINARY_CHUNK
                 _isLastChunk = tag == 'B';
                 _chunkLength = (read() << 8) + read();
                 break;
@@ -3385,7 +3392,10 @@
                 _isLastChunk = true;
                 _chunkLength = tag - 0x20;
                 break;
-
+            case 0x34: case 0x35: case 0x36: case 0x37:
+                _isLastChunk = true;
+                _chunkLength = (tag - 0x34) * 256 + read();
+                break;
             default:
                 throw expect("binary", tag);
         }
@@ -3408,13 +3418,14 @@
                 int code = read();
 
                 switch (code) {
-                    case 'b':
+                    case BC_BINARY_CHUNK:
+                    case 'b': //maybe it's a mistype of BC_BINARY_CHUNK
                         _isLastChunk = false;
 
                         _chunkLength = (read() << 8) + read();
                         break;
 
-                    case 'B':
+                    case BC_BINARY:
                         _isLastChunk = true;
 
                         _chunkLength = (read() << 8) + read();
@@ -3439,7 +3450,10 @@
                         _isLastChunk = true;
                         _chunkLength = code - 0x20;
                         break;
-
+                    case 0x34: case 0x35: case 0x36: case 0x37:
+                        _isLastChunk = true;
+                        _chunkLength = (code - 0x34) * 256 + read();
+                        break;
                     default:
                         throw expect("byte[]", code);
                 }
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianInput.java b/src/main/java/com/alibaba/com/caucho/hessian/io/HessianInput.java
index ffc1732..14b3096 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianInput.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/HessianInput.java
@@ -170,6 +170,11 @@
         return _replyFault;
     }
 
+    @Override
+    public boolean checkAndReadNull() {
+        return _peek == 'N';
+    }
+
     /**
      * Starts reading the call
      * <p>
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/SerializerFactory.java b/src/main/java/com/alibaba/com/caucho/hessian/io/SerializerFactory.java
index 8ac5fde..20c4187 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/SerializerFactory.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/SerializerFactory.java
@@ -80,6 +80,7 @@
 import java.util.Locale;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -94,7 +95,7 @@
 
     private static Deserializer OBJECT_DESERIALIZER
             = new BasicDeserializer(BasicDeserializer.OBJECT);
-
+    private static ConcurrentHashMap _unrecognizedTypeCache = new ConcurrentHashMap();
     private static HashMap _staticSerializerMap;
     private static HashMap _staticDeserializerMap;
     private static HashMap _staticTypeMap;
@@ -647,7 +648,7 @@
                 deserializer = new ArrayDeserializer(subDeserializer.getType());
             else
                 deserializer = new ArrayDeserializer(Object.class);
-        } else {
+        } else if (_unrecognizedTypeCache.get(type) == null) {
             try {
                 Class cl = Class.forName(type, false, _loader);
                 deserializer = getDeserializer(cl);
@@ -655,7 +656,12 @@
                 log.warning("Hessian/Burlap: '" + type + "' is an unknown class in " + _loader + ":\n" + e);
                 _typeNotFoundDeserializerMap.put(type, PRESENT);
                 log.log(Level.FINER, e.toString(), e);
+                _unrecognizedTypeCache.put(type, new AtomicLong(1L));
             }
+        } else {
+            ((AtomicLong) _unrecognizedTypeCache.get(type)).incrementAndGet();
+            if (((AtomicLong) _unrecognizedTypeCache.get(type)).get() % 2000L == 0L)
+                ((AtomicLong) _unrecognizedTypeCache.get(type)).getAndSet(1L);
         }
 
         if (deserializer != null) {
diff --git a/src/test/java/com/alibaba/com/caucho/hessian/io/CollectionSerializerTest.java b/src/test/java/com/alibaba/com/caucho/hessian/io/CollectionSerializerTest.java
index 0b20240..75aa608 100644
--- a/src/test/java/com/alibaba/com/caucho/hessian/io/CollectionSerializerTest.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian/io/CollectionSerializerTest.java
@@ -17,15 +17,18 @@
 package com.alibaba.com.caucho.hessian.io;
 
 import com.alibaba.com.caucho.hessian.io.base.SerializeTestBase;
-
-import org.junit.Assert;
-import org.junit.Test;
-
+import com.alibaba.com.caucho.hessian.io.beans.SubUser;
+import java.io.IOException;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
 import java.util.Vector;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.junit.Assert;
+import org.junit.Test;
 
 public class CollectionSerializerTest extends SerializeTestBase {
     @Test
@@ -40,6 +43,46 @@
     }
 
     @Test
+    public void testSubUser() throws IOException {
+        int times = 100;
+        final CountDownLatch latch = new CountDownLatch(times);
+        final AtomicInteger error = new AtomicInteger();
+        for (int i = 0; i < times; i++) {
+           new Thread(new Runnable() {
+                @Override
+                public void run() {
+                    for (int j = 0; j < 100; j++) {
+                        try {
+                            SubUser subUser = new SubUser();
+                            subUser.setUserId(1);
+                            subUser.setUserName("tony");
+                            List<Integer> list1 = Arrays.asList(null, 3, 1);
+                            List<Double> list2 = Arrays.asList(null, 1.1, 1.2);
+                            List<Boolean> list3 = Arrays.asList(false, null, true);
+                            subUser.setAgeList(list1);
+                            subUser.setWeightList(list2);
+                            subUser.setSexyList(list3);
+                            SubUser serializeUser = baseHessian2Serialize(subUser);
+                            Assert.assertEquals(subUser.getAgeList(), serializeUser.getAgeList());
+                            Assert.assertEquals(subUser.getWeightList(), serializeUser.getWeightList());
+                            Assert.assertEquals(subUser.getSexyList(), serializeUser.getSexyList());
+                        } catch (Throwable e) {
+                            error.incrementAndGet();
+                        }
+                    }
+                    latch.countDown();
+                }
+            }).start();
+        }
+        try {
+            latch.await();
+            Assert.assertEquals(0, error.get());
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Test
     public void testListSerializer() throws Exception {
 
         List<Integer> list = new LinkedList<>();
diff --git a/src/test/java/com/alibaba/com/caucho/hessian/io/HessianJavaSerializeTest.java b/src/test/java/com/alibaba/com/caucho/hessian/io/HessianJavaSerializeTest.java
index abe66a9..5bb08a3 100644
--- a/src/test/java/com/alibaba/com/caucho/hessian/io/HessianJavaSerializeTest.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian/io/HessianJavaSerializeTest.java
@@ -66,10 +66,10 @@
         list.add(null);
         list.add(null);
         list.add(3);
-        subUser.setWage(list);
+        subUser.setAgeList(list);
 
         SubUser serializedUser = baseHessian2Serialize(subUser);
-        Assert.assertEquals(subUser.getWage(), serializedUser.getWage());
+        Assert.assertEquals(subUser.getAgeList(), serializedUser.getAgeList());
 
     }
 
diff --git a/src/test/java/com/alibaba/com/caucho/hessian/io/beans/SubUser.java b/src/test/java/com/alibaba/com/caucho/hessian/io/beans/SubUser.java
index 5f988cf..7553f48 100644
--- a/src/test/java/com/alibaba/com/caucho/hessian/io/beans/SubUser.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian/io/beans/SubUser.java
@@ -25,7 +25,9 @@
 public class SubUser extends BaseUser implements Serializable {
     private static final long serialVersionUID = 4017613093053853415L;
     private String userName;
-    private List<Integer> wage;
+    private List<Integer> ageList;
+    private List<Double> weightList;
+    private List<Boolean> sexyList;
 
     @Override
     public String getUserName() {
@@ -37,11 +39,27 @@
         this.userName = userName;
     }
 
-    public List<Integer> getWage() {
-        return wage;
+    public List<Integer> getAgeList() {
+        return ageList;
     }
 
-    public void setWage(List<Integer> wage) {
-        this.wage = wage;
+    public void setAgeList(List<Integer> ageList) {
+        this.ageList = ageList;
+    }
+
+    public List<Double> getWeightList() {
+        return weightList;
+    }
+
+    public void setWeightList(List<Double> weightList) {
+        this.weightList = weightList;
+    }
+
+    public List<Boolean> getSexyList() {
+        return sexyList;
+    }
+
+    public void setSexyList(List<Boolean> sexyList) {
+        this.sexyList = sexyList;
     }
 }