Merge pull request #7 from hopelove404/hessian-optimize-typenotfound

Fix performance overhead caused by too much unknown classloading during hessian2 deserialization
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 b233fdb..5459718 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
@@ -70,15 +70,7 @@
 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Locale;
-import java.util.Map;
+import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -231,6 +223,12 @@
     private ConcurrentHashMap _cachedDeserializerMap;
     private ConcurrentHashMap _cachedTypeDeserializerMap;
     private boolean _isAllowNonSerializable;
+    /**
+     * For those classes are unknown in current classloader, record them in this set to avoid
+     * frequently class loading and to reduce performance overhead.
+     */
+    private Map<String, Object> _typeNotFoundDeserializerMap = new ConcurrentHashMap<>(8);
+    private static final Object PRESENT = new Object();
 
     public SerializerFactory() {
         this(Thread.currentThread().getContextClassLoader());
@@ -617,7 +615,7 @@
      */
     public Deserializer getDeserializer(String type)
             throws HessianProtocolException {
-        if (type == null || type.equals(""))
+        if (type == null || type.equals("") || _typeNotFoundDeserializerMap.containsKey(type))
             return null;
 
         Deserializer deserializer;
@@ -647,7 +645,7 @@
                 deserializer = getDeserializer(cl);
             } catch (Exception e) {
                 log.warning("Hessian/Burlap: '" + type + "' is an unknown class in " + _loader + ":\n" + e);
-
+                _typeNotFoundDeserializerMap.put(type, PRESENT);
                 log.log(Level.FINER, e.toString(), e);
             }
         }
diff --git a/src/test/java/com/alibaba/com/caucho/hessian/io/SerializerFactoryTest.java b/src/test/java/com/alibaba/com/caucho/hessian/io/SerializerFactoryTest.java
index 652f8ef..36b32c5 100644
--- a/src/test/java/com/alibaba/com/caucho/hessian/io/SerializerFactoryTest.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian/io/SerializerFactoryTest.java
@@ -99,4 +99,18 @@
         countDownLatch.await();
     }
 
+    @Test
+    public void getDeserializerByType() throws Exception {
+        final SerializerFactory serializerFactory = new SerializerFactory();
+
+        final String testClassName = TestClass.class.getName();
+        Deserializer d1 = serializerFactory.getDeserializer(testClassName);
+        Assert.assertTrue("TestClass Deserializer!", d1 != null);
+
+        Deserializer d2 = serializerFactory.getDeserializer("com.test.NotExistClass");
+        Assert.assertTrue("NotExistClass Deserializer!", d2 == null);
+        //again check NotExistClass, there should be no warning like Hessian/Burlap:.....
+        Deserializer d3 = serializerFactory.getDeserializer("com.test.NotExistClass");
+        Assert.assertTrue("NotExistClass Deserializer!", d3 == null);
+    }
 }
\ No newline at end of file