Merge pull request #1843, support implicit delivery of attachments from provider to consumer.

Fixes #889, #1466, #1834, #1466, #1524
diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java
index 44c751d..ec86f1d 100644
--- a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java
+++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java
@@ -101,10 +101,10 @@
 

         private Invoker<T> selectForKey(long hash) {

             Map.Entry<Long, Invoker<T>> entry = virtualInvokers.tailMap(hash, true).firstEntry();

-        	if (entry == null) {

-        		entry = virtualInvokers.firstEntry();

-        	}

-        	return entry.getValue();

+            if (entry == null) {

+                entry = virtualInvokers.firstEntry();

+            }

+            return entry.getValue();

         }

 

         private long hash(byte[] digest, int number) {

diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java
index 55e86d0..404fe8f 100644
--- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java
+++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java
@@ -156,7 +156,7 @@
 
     public static final String LOADBALANCE_KEY = "loadbalance";
 
-    // key for router type, for e.g., "script"/"file",  corresponding to ScriptRouterFactory.NAME, FileRouterFactory.NAME 
+    // key for router type, for e.g., "script"/"file",  corresponding to ScriptRouterFactory.NAME, FileRouterFactory.NAME
     public static final String ROUTER_KEY = "router";
 
     public static final String CLUSTER_KEY = "cluster";
@@ -624,7 +624,7 @@
     public static final String QOS_PORT = "qos.port";
 
     public static final String ACCEPT_FOREIGN_IP = "qos.accept.foreign.ip";
-    
+
     public static final String HESSIAN2_REQUEST_KEY = "hessian2.request";
 
     public static final boolean DEFAULT_HESSIAN2_REQUEST = false;
diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Version.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Version.java
index 97e3a21..b84aaa5 100644
--- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Version.java
+++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Version.java
@@ -23,17 +23,28 @@
 import java.net.URL;
 import java.security.CodeSource;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 
 /**
  * Version
  */
 public final class Version {
-
-    private static final String DEFAULT_DUBBO_VERSION = "2.0.0";
     private static final Logger logger = LoggerFactory.getLogger(Version.class);
-    private static final String VERSION = getVersion(Version.class, DEFAULT_DUBBO_VERSION);
+
+    // Dubbo RPC protocol version
+    public static final String DEFAULT_DUBBO_PROTOCOL_VERSION = "2.0.2";
+    // Dubbo implementation version, usually is jar version.
+    private static final String VERSION = getVersion(Version.class, "");
+
+    /**
+     * For protocol compatibility purpose.
+     * Because {@link #isSupportResponseAttatchment} is checked for every call, int compare expect to has higher performance than string.
+     */
+    private static final int LOWEST_VERSION_FOR_RESPONSE_ATTATCHMENT = 202; // 2.0.2
+    private static final Map<String, Integer> VERSION2INT = new HashMap<String, Integer>();
 
     static {
         // check if there's duplicated jar
@@ -43,10 +54,39 @@
     private Version() {
     }
 
+    public static String getProtocolVersion() {
+        return DEFAULT_DUBBO_PROTOCOL_VERSION;
+    }
+
     public static String getVersion() {
         return VERSION;
     }
 
+    public static boolean isSupportResponseAttatchment(String version) {
+        if (version == null || version.length() == 0) {
+            return false;
+        }
+        return getIntVersion(version) >= LOWEST_VERSION_FOR_RESPONSE_ATTATCHMENT;
+    }
+
+    public static int getIntVersion(String version) {
+        Integer v = VERSION2INT.get(version);
+        if (v == null) {
+            v = parseInt(version);
+            VERSION2INT.put(version, v);
+        }
+        return v;
+    }
+
+    private static int parseInt(String version) {
+        int v = 0;
+        String[] vArr = version.split("\\.");
+        int len = vArr.length;
+        for (int i = 1; i <= len; i++) {
+            v += Integer.parseInt(vArr[len - i]) * Math.pow(10, i - 1);
+        }
+        return v;
+    }
 
     private static boolean hasResource(String path) {
         try {
diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/version/VersionTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/version/VersionTest.java
new file mode 100644
index 0000000..139216b
--- /dev/null
+++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/version/VersionTest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 com.alibaba.dubbo.common.version;
+
+
+import com.alibaba.dubbo.common.Version;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class VersionTest {
+
+    @Test
+    public void testGetProtocolVersion() {
+        Assert.assertEquals(Version.getProtocolVersion(), Version.DEFAULT_DUBBO_PROTOCOL_VERSION);
+    }
+
+    @Test
+    public void testSupportResponseAttatchment() {
+        Assert.assertTrue(Version.isSupportResponseAttatchment("2.0.2"));
+        Assert.assertTrue(Version.isSupportResponseAttatchment("2.0.3"));
+        Assert.assertFalse(Version.isSupportResponseAttatchment("2.0.0"));
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractInterfaceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractInterfaceConfig.java
index a42d07c..168bb10 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractInterfaceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/AbstractInterfaceConfig.java
@@ -174,7 +174,7 @@
                     appendParameters(map, application);

                     appendParameters(map, config);

                     map.put("path", RegistryService.class.getName());

-                    map.put("dubbo", Version.getVersion());

+                    map.put("dubbo", Version.getProtocolVersion());

                     map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));

                     if (ConfigUtils.getPid() > 0) {

                         map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));

@@ -220,7 +220,7 @@
         appendProperties(monitor);

         Map<String, String> map = new HashMap<String, String>();

         map.put(Constants.INTERFACE_KEY, MonitorService.class.getName());

-        map.put("dubbo", Version.getVersion());

+        map.put("dubbo", Version.getProtocolVersion());

         map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));

         if (ConfigUtils.getPid() > 0) {

             map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));

diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java
index 7b51752..c6c75b1 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java
@@ -280,7 +280,7 @@
         Map<String, String> map = new HashMap<String, String>();

         Map<Object, Object> attributes = new HashMap<Object, Object>();

         map.put(Constants.SIDE_KEY, Constants.CONSUMER_SIDE);

-        map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion());

+        map.put(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion());

         map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));

         if (ConfigUtils.getPid() > 0) {

             map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));

diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ServiceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ServiceConfig.java
index d04d51c..8637662 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ServiceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ServiceConfig.java
@@ -367,7 +367,7 @@
 

         Map<String, String> map = new HashMap<String, String>();

         map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE);

-        map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion());

+        map.put(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion());

         map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));

         if (ConfigUtils.getPid() > 0) {

             map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));

diff --git a/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/cache/CacheTest.java b/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/cache/CacheTest.java
index 521642e..ebda6ba 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/cache/CacheTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/cache/CacheTest.java
@@ -29,6 +29,7 @@
 import com.alibaba.dubbo.config.ServiceConfig;

 import com.alibaba.dubbo.rpc.Invocation;

 import com.alibaba.dubbo.rpc.RpcInvocation;

+

 import junit.framework.TestCase;

 import org.junit.Test;

 

diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/schema/DubboBeanDefinitionParser.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/schema/DubboBeanDefinitionParser.java
index c9c912d..48192a9 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/schema/DubboBeanDefinitionParser.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/schema/DubboBeanDefinitionParser.java
@@ -31,6 +31,7 @@
 import com.alibaba.dubbo.config.spring.ReferenceBean;
 import com.alibaba.dubbo.config.spring.ServiceBean;
 import com.alibaba.dubbo.rpc.Protocol;
+
 import org.springframework.beans.PropertyValue;
 import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.beans.factory.config.BeanDefinitionHolder;
@@ -213,7 +214,7 @@
                                     String invokeRefMethod = value.substring(index + 1);
                                     reference = new RuntimeBeanReference(invokeRef);
                                     beanDefinition.getPropertyValues().addPropertyValue("oninvokeMethod", invokeRefMethod);
-                                }else {
+                                } else {
                                     if ("ref".equals(property) && parserContext.getRegistry().containsBeanDefinition(value)) {
                                         BeanDefinition refBean = parserContext.getRegistry().getBeanDefinition(value);
                                         if (!refBean.isSingleton()) {
diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/codec/ExchangeCodec.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/codec/ExchangeCodec.java
index 10025d2..c1b8e09 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/codec/ExchangeCodec.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/codec/ExchangeCodec.java
@@ -16,6 +16,7 @@
  */

 package com.alibaba.dubbo.remoting.exchange.codec;

 

+import com.alibaba.dubbo.common.Version;

 import com.alibaba.dubbo.common.io.Bytes;

 import com.alibaba.dubbo.common.io.StreamUtils;

 import com.alibaba.dubbo.common.logger.Logger;

@@ -173,7 +174,7 @@
         } else {

             // decode request.

             Request req = new Request(id);

-            req.setVersion("2.0.0");

+            req.setVersion(Version.getProtocolVersion());

             req.setTwoWay((flag & FLAG_TWOWAY) != 0);

             if ((flag & FLAG_EVENT) != 0) {

                 req.setEvent(Request.HEARTBEAT_EVENT);

@@ -231,7 +232,7 @@
         if (req.isEvent()) {

             encodeEventData(channel, out, req.getData());

         } else {

-            encodeRequestData(channel, out, req.getData());

+            encodeRequestData(channel, out, req.getData(), req.getVersion());

         }

         out.flushBuffer();

         if (out instanceof Cleanable) {

@@ -274,7 +275,7 @@
                 if (res.isHeartbeat()) {

                     encodeHeartbeatData(channel, out, res.getResult());

                 } else {

-                    encodeResponseData(channel, out, res.getResult());

+                    encodeResponseData(channel, out, res.getResult(), res.getVersion());

                 }

             } else out.writeUTF(res.getErrorMessage());

             out.flushBuffer();

@@ -442,4 +443,13 @@
         encodeResponseData(out, data);

     }

 

+    protected void encodeRequestData(Channel channel, ObjectOutput out, Object data, String version) throws IOException {

+        encodeRequestData(out, data);

+    }

+

+    protected void encodeResponseData(Channel channel, ObjectOutput out, Object data, String version) throws IOException {

+        encodeResponseData(out, data);

+    }

+

+

 }

diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeChannel.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeChannel.java
index 7b6bd8c..3c0fb65 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeChannel.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeChannel.java
@@ -18,6 +18,7 @@
 

 import com.alibaba.dubbo.common.Constants;

 import com.alibaba.dubbo.common.URL;

+import com.alibaba.dubbo.common.Version;

 import com.alibaba.dubbo.common.logger.Logger;

 import com.alibaba.dubbo.common.logger.LoggerFactory;

 import com.alibaba.dubbo.remoting.Channel;

@@ -88,7 +89,7 @@
             channel.send(message, sent);

         } else {

             Request request = new Request();

-            request.setVersion("2.0.0");

+            request.setVersion(Version.getProtocolVersion());

             request.setTwoWay(false);

             request.setData(message);

             channel.send(request, sent);

@@ -107,7 +108,7 @@
         }

         // create request.

         Request req = new Request();

-        req.setVersion("2.0.0");

+        req.setVersion(Version.getProtocolVersion());

         req.setTwoWay(true);

         req.setData(request);

         DefaultFuture future = new DefaultFuture(channel, req, timeout);

diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java
index 2ab32f0..6e520e3 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java
@@ -29,6 +29,7 @@
 import com.alibaba.dubbo.remoting.exchange.ExchangeChannel;

 import com.alibaba.dubbo.remoting.exchange.ExchangeServer;

 import com.alibaba.dubbo.remoting.exchange.Request;

+

 import java.net.InetSocketAddress;

 import java.util.ArrayList;

 import java.util.Collection;

@@ -133,7 +134,7 @@
         Request request = new Request();

         request.setEvent(Request.READONLY_EVENT);

         request.setTwoWay(false);

-        request.setVersion(Version.getVersion());

+        request.setVersion(Version.getProtocolVersion());

 

         Collection<Channel> channels = getChannels();

         for (Channel channel : channels) {

diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeartBeatTask.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeartBeatTask.java
index ce529b9..5dd00d6 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeartBeatTask.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeartBeatTask.java
@@ -17,6 +17,7 @@
 
 package com.alibaba.dubbo.remoting.exchange.support.header;
 
+import com.alibaba.dubbo.common.Version;
 import com.alibaba.dubbo.common.logger.Logger;
 import com.alibaba.dubbo.common.logger.LoggerFactory;
 import com.alibaba.dubbo.remoting.Channel;
@@ -57,7 +58,7 @@
                     if ((lastRead != null && now - lastRead > heartbeat)
                             || (lastWrite != null && now - lastWrite > heartbeat)) {
                         Request req = new Request();
-                        req.setVersion("2.0.0");
+                        req.setVersion(Version.getProtocolVersion());
                         req.setTwoWay(true);
                         req.setEvent(Request.HEARTBEAT_EVENT);
                         channel.send(req);
diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/codec/ExchangeCodecTest.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/codec/ExchangeCodecTest.java
index 0f36da4..e372e14 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/codec/ExchangeCodecTest.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/codec/ExchangeCodecTest.java
@@ -18,6 +18,7 @@
 
 
 import com.alibaba.dubbo.common.Constants;
+import com.alibaba.dubbo.common.Version;
 import com.alibaba.dubbo.common.extension.ExtensionLoader;
 import com.alibaba.dubbo.common.io.Bytes;
 import com.alibaba.dubbo.common.io.UnsafeByteArrayOutputStream;
@@ -216,7 +217,7 @@
         Assert.assertEquals(person, obj.getData());
         Assert.assertEquals(true, obj.isTwoWay());
         Assert.assertEquals(true, obj.isEvent());
-        Assert.assertEquals("2.0.0", obj.getVersion());
+        Assert.assertEquals(Version.getProtocolVersion(), obj.getVersion());
         System.out.println(obj);
     }
 
@@ -231,7 +232,7 @@
         Assert.assertEquals(event, obj.getData());
         Assert.assertEquals(true, obj.isTwoWay());
         Assert.assertEquals(true, obj.isEvent());
-        Assert.assertEquals("2.0.0", obj.getVersion());
+        Assert.assertEquals(Version.getProtocolVersion(), obj.getVersion());
         System.out.println(obj);
     }
 
@@ -244,7 +245,7 @@
         Assert.assertEquals(null, obj.getData());
         Assert.assertEquals(true, obj.isTwoWay());
         Assert.assertEquals(true, obj.isHeartbeat());
-        Assert.assertEquals("2.0.0", obj.getVersion());
+        Assert.assertEquals(Version.getProtocolVersion(), obj.getVersion());
         System.out.println(obj);
     }
 
@@ -259,7 +260,7 @@
         Assert.assertEquals(person, obj.getData());
         Assert.assertEquals(true, obj.isTwoWay());
         Assert.assertEquals(false, obj.isHeartbeat());
-        Assert.assertEquals("2.0.0", obj.getVersion());
+        Assert.assertEquals(Version.getProtocolVersion(), obj.getVersion());
         System.out.println(obj);
     }
 
@@ -350,7 +351,7 @@
         Assert.assertEquals(response.isHeartbeat(), obj.isHeartbeat());
         Assert.assertEquals(person, obj.getResult());
         // encode response verson ??
-//        Assert.assertEquals(response.getVersion(), obj.getVersion());
+//        Assert.assertEquals(response.getProtocolVersion(), obj.getVersion());
 
     }
 
@@ -380,7 +381,7 @@
         Assert.assertEquals(response.isHeartbeat(), obj.isHeartbeat());
         Assert.assertEquals(badString, obj.getErrorMessage());
         Assert.assertEquals(null, obj.getResult());
-//        Assert.assertEquals(response.getVersion(), obj.getVersion());
+//        Assert.assertEquals(response.getProtocolVersion(), obj.getVersion());
     }
 
     // http://code.alibabatech.com/jira/browse/DUBBO-392
@@ -388,7 +389,7 @@
     public void testMessageLengthGreaterThanMessageActualLength() throws Exception {
         Channel channel = getCliendSideChannel(url);
         Request request = new Request(1L);
-        request.setVersion("2.0.0");
+        request.setVersion(Version.getProtocolVersion());
         Date date = new Date();
         request.setData(date);
         ChannelBuffer encodeBuffer = ChannelBuffers.dynamicBuffer(1024);
diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/transport/codec/DeprecatedExchangeCodec.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/transport/codec/DeprecatedExchangeCodec.java
index d70edb1..2b44ada 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/transport/codec/DeprecatedExchangeCodec.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/transport/codec/DeprecatedExchangeCodec.java
@@ -16,6 +16,7 @@
  */
 package com.alibaba.dubbo.remoting.transport.codec;
 
+import com.alibaba.dubbo.common.Version;
 import com.alibaba.dubbo.common.io.Bytes;
 import com.alibaba.dubbo.common.io.StreamUtils;
 import com.alibaba.dubbo.common.io.UnsafeByteArrayInputStream;
@@ -164,7 +165,7 @@
         } else {
             // decode request.
             Request req = new Request(id);
-            req.setVersion("2.0.0");
+            req.setVersion(Version.getProtocolVersion());
             req.setTwoWay((flag & FLAG_TWOWAY) != 0);
             if ((flag & FLAG_EVENT) != 0) {
                 req.setEvent(Request.HEARTBEAT_EVENT);
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java
index bf56e2d..6bb4d86 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java
@@ -55,6 +55,12 @@
             return new RpcContext();

         }

     };

+    private static final InternalThreadLocal<RpcContext> SERVER_LOCAL = new InternalThreadLocal<RpcContext>() {

+        @Override

+        protected RpcContext initialValue() {

+            return new RpcContext();

+        }

+    };

 

     private final Map<String, String> attachments = new HashMap<String, String>();

     private final Map<String, Object> values = new HashMap<String, Object>();

@@ -89,6 +95,24 @@
     }

 

     /**

+     * get server side context.

+     *

+     * @return server context

+     */

+    public static RpcContext getServerContext() {

+        return SERVER_LOCAL.get();

+    }

+

+    /**

+     * remove server side context.

+     *

+     * @see com.alibaba.dubbo.rpc.filter.ContextFilter

+     */

+    public static void removeServerContext() {

+        SERVER_LOCAL.remove();

+    }

+

+    /**

      * get context.

      *

      * @return context

diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcResult.java
index ac4504a..8d3811b 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcResult.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcResult.java
@@ -107,9 +107,17 @@
      * @param map contains all key-value pairs to append
      */
     public void setAttachments(Map<String, String> map) {
-        if (map != null && map.size() > 0) {
-            attachments.putAll(map);
+        this.attachments = map == null ? new HashMap<String, String>() : map;
+    }
+
+    public void addAttachments(Map<String, String> map) {
+        if (map == null) {
+            return;
         }
+        if (this.attachments == null) {
+            this.attachments = new HashMap<String, String>();
+        }
+        this.attachments.putAll(map);
     }
 
     @Override
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ConsumerContextFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ConsumerContextFilter.java
index ba2cd75..8c9f822 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ConsumerContextFilter.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ConsumerContextFilter.java
@@ -26,6 +26,7 @@
 import com.alibaba.dubbo.rpc.RpcContext;

 import com.alibaba.dubbo.rpc.RpcException;

 import com.alibaba.dubbo.rpc.RpcInvocation;

+import com.alibaba.dubbo.rpc.RpcResult;

 

 /**

  * ConsumerContextInvokerFilter

@@ -45,7 +46,9 @@
             ((RpcInvocation) invocation).setInvoker(invoker);

         }

         try {

-            return invoker.invoke(invocation);

+            RpcResult result = (RpcResult) invoker.invoke(invocation);

+            RpcContext.getServerContext().setAttachments(result.getAttachments());

+            return result;

         } finally {

             RpcContext.getContext().clearAttachments();

         }

diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ContextFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ContextFilter.java
index d0b7da1..ed852bf 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ContextFilter.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ContextFilter.java
@@ -25,6 +25,7 @@
 import com.alibaba.dubbo.rpc.RpcContext;

 import com.alibaba.dubbo.rpc.RpcException;

 import com.alibaba.dubbo.rpc.RpcInvocation;

+import com.alibaba.dubbo.rpc.RpcResult;

 

 import java.util.HashMap;

 import java.util.Map;

@@ -69,9 +70,13 @@
             ((RpcInvocation) invocation).setInvoker(invoker);

         }

         try {

-            return invoker.invoke(invocation);

+            RpcResult result = (RpcResult) invoker.invoke(invocation);

+            // pass attachments to result

+            result.addAttachments(RpcContext.getServerContext().getAttachments());

+            return result;

         } finally {

             RpcContext.removeContext();

+            RpcContext.getServerContext().clearAttachments();

         }

     }

 }

diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcInvocation.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcInvocation.java
index 7fdaf83..4002f04 100644
--- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcInvocation.java
+++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcInvocation.java
@@ -90,7 +90,10 @@
         ObjectInput in = CodecSupport.getSerialization(channel.getUrl(), serializationType)
                 .deserialize(channel.getUrl(), input);
 
-        setAttachment(Constants.DUBBO_VERSION_KEY, in.readUTF());
+        String dubboVersion = in.readUTF();
+        request.setVersion(dubboVersion);
+        setAttachment(Constants.DUBBO_VERSION_KEY, dubboVersion);
+
         setAttachment(Constants.PATH_KEY, in.readUTF());
         setAttachment(Constants.VERSION_KEY, in.readUTF());
 
diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcResult.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcResult.java
index 9e84e88..f774557 100644
--- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcResult.java
+++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcResult.java
@@ -35,6 +35,7 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.lang.reflect.Type;
+import java.util.Map;
 
 public class DecodeableRpcResult extends RpcResult implements Codec, Decodeable {
 
@@ -97,6 +98,35 @@
                     throw new IOException(StringUtils.toString("Read response data failed.", e));
                 }
                 break;
+            case DubboCodec.RESPONSE_NULL_VALUE_WITH_ATTACHMENTS:
+                try {
+                    setAttachments((Map<String, String>) in.readObject(Map.class));
+                } catch (ClassNotFoundException e) {
+                    throw new IOException(StringUtils.toString("Read response data failed.", e));
+                }
+                break;
+            case DubboCodec.RESPONSE_VALUE_WITH_ATTACHMENTS:
+                try {
+                    Type[] returnType = RpcUtils.getReturnTypes(invocation);
+                    setValue(returnType == null || returnType.length == 0 ? in.readObject() :
+                            (returnType.length == 1 ? in.readObject((Class<?>) returnType[0])
+                                    : in.readObject((Class<?>) returnType[0], returnType[1])));
+                    setAttachments((Map<String, String>) in.readObject(Map.class));
+                } catch (ClassNotFoundException e) {
+                    throw new IOException(StringUtils.toString("Read response data failed.", e));
+                }
+                break;
+            case DubboCodec.RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS:
+                try {
+                    Object obj = in.readObject();
+                    if (obj instanceof Throwable == false)
+                        throw new IOException("Response data error, expect Throwable, but get " + obj);
+                    setException((Throwable) obj);
+                    setAttachments((Map<String, String>) in.readObject(Map.class));
+                } catch (ClassNotFoundException e) {
+                    throw new IOException(StringUtils.toString("Read response data failed.", e));
+                }
+                break;
             default:
                 throw new IOException("Unknown result flag, expect '0' '1' '2', get " + flag);
         }
diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodec.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodec.java
index 8c633f7..80e4209 100644
--- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodec.java
+++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodec.java
@@ -49,10 +49,13 @@
 public class DubboCodec extends ExchangeCodec implements Codec2 {
 
     public static final String NAME = "dubbo";
-    public static final String DUBBO_VERSION = Version.getVersion(DubboCodec.class, Version.getVersion());
+    public static final String DUBBO_VERSION = Version.getProtocolVersion();
     public static final byte RESPONSE_WITH_EXCEPTION = 0;
     public static final byte RESPONSE_VALUE = 1;
     public static final byte RESPONSE_NULL_VALUE = 2;
+    public static final byte RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS = 3;
+    public static final byte RESPONSE_VALUE_WITH_ATTACHMENTS = 4;
+    public static final byte RESPONSE_NULL_VALUE_WITH_ATTACHMENTS = 5;
     public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
     public static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
     private static final Logger log = LoggerFactory.getLogger(DubboCodec.class);
@@ -109,7 +112,7 @@
         } else {
             // decode request.
             Request req = new Request(id);
-            req.setVersion("2.0.0");
+            req.setVersion(Version.getProtocolVersion());
             req.setTwoWay((flag & FLAG_TWOWAY) != 0);
             if ((flag & FLAG_EVENT) != 0) {
                 req.setEvent(Request.HEARTBEAT_EVENT);
@@ -162,9 +165,19 @@
 
     @Override
     protected void encodeRequestData(Channel channel, ObjectOutput out, Object data) throws IOException {
+        encodeRequestData(channel, out, data, DUBBO_VERSION);
+    }
+
+    @Override
+    protected void encodeResponseData(Channel channel, ObjectOutput out, Object data) throws IOException {
+        encodeResponseData(channel, out, data, DUBBO_VERSION);
+    }
+
+    @Override
+    protected void encodeRequestData(Channel channel, ObjectOutput out, Object data, String version) throws IOException {
         RpcInvocation inv = (RpcInvocation) data;
 
-        out.writeUTF(inv.getAttachment(Constants.DUBBO_VERSION_KEY, DUBBO_VERSION));
+        out.writeUTF(version);
         out.writeUTF(inv.getAttachment(Constants.PATH_KEY));
         out.writeUTF(inv.getAttachment(Constants.VERSION_KEY));
 
@@ -179,21 +192,28 @@
     }
 
     @Override
-    protected void encodeResponseData(Channel channel, ObjectOutput out, Object data) throws IOException {
+    protected void encodeResponseData(Channel channel, ObjectOutput out, Object data, String version) throws IOException {
         Result result = (Result) data;
-
+        // currently, the version value in Response records the version of Request
+        boolean attach = Version.isSupportResponseAttatchment(version);
         Throwable th = result.getException();
         if (th == null) {
             Object ret = result.getValue();
             if (ret == null) {
-                out.writeByte(RESPONSE_NULL_VALUE);
+                out.writeByte(attach ? RESPONSE_NULL_VALUE_WITH_ATTACHMENTS : RESPONSE_NULL_VALUE);
             } else {
-                out.writeByte(RESPONSE_VALUE);
+                out.writeByte(attach ? RESPONSE_VALUE_WITH_ATTACHMENTS : RESPONSE_VALUE);
                 out.writeObject(ret);
             }
         } else {
-            out.writeByte(RESPONSE_WITH_EXCEPTION);
+            out.writeByte(attach ? RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS : RESPONSE_WITH_EXCEPTION);
             out.writeObject(th);
         }
+
+        if (attach) {
+            // returns current version of Response to consumer side.
+            result.getAttachments().put(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion());
+            out.writeObject(result.getAttachments());
+        }
     }
 }
diff --git a/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianProtocolTest.java b/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianProtocolTest.java
index 6e8ab72..877ecd3 100644
--- a/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianProtocolTest.java
+++ b/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianProtocolTest.java
@@ -51,7 +51,7 @@
         invoker.destroy();

         exporter.unexport();

     }

-    

+

     @Test

     public void testOverload() {

         HessianServiceImpl server = new HessianServiceImpl();

diff --git a/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianService.java b/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianService.java
index c2f05d2..8629425 100644
--- a/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianService.java
+++ b/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianService.java
@@ -23,7 +23,7 @@
 public interface HessianService {

 

     String sayHello(String name);

-    

+

     String sayHello(String name, int times);

 

     void timeOut(int millis);

diff --git a/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianServiceImpl.java b/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianServiceImpl.java
index cc1fe3c..855de0a 100644
--- a/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianServiceImpl.java
+++ b/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianServiceImpl.java
@@ -27,7 +27,7 @@
         called = true;

         return "Hello, " + name;

     }

-    

+

     public String sayHello(String name, int times) {

         called = true;

         StringBuilder sb = new StringBuilder();

diff --git a/dubbo-rpc/dubbo-rpc-rmi/src/main/java/com/alibaba/dubbo/rpc/protocol/rmi/RmiProtocol.java b/dubbo-rpc/dubbo-rpc-rmi/src/main/java/com/alibaba/dubbo/rpc/protocol/rmi/RmiProtocol.java
index 8b01c1d..55fe932 100644
--- a/dubbo-rpc/dubbo-rpc-rmi/src/main/java/com/alibaba/dubbo/rpc/protocol/rmi/RmiProtocol.java
+++ b/dubbo-rpc/dubbo-rpc-rmi/src/main/java/com/alibaba/dubbo/rpc/protocol/rmi/RmiProtocol.java
@@ -78,7 +78,7 @@
     protected <T> T doRefer(final Class<T> serviceType, final URL url) throws RpcException {

         final RmiProxyFactoryBean rmiProxyFactoryBean = new RmiProxyFactoryBean();

         // RMI needs extra parameter since it uses customized remote invocation object

-        if (url.getParameter(Constants.DUBBO_VERSION_KEY, Version.getVersion()).equals(Version.getVersion())) {

+        if (url.getParameter(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion()).equals(Version.getProtocolVersion())) {

             // Check dubbo version on provider, this feature only support

             rmiProxyFactoryBean.setRemoteInvocationFactory(new RemoteInvocationFactory() {

                 @Override

diff --git a/dubbo-rpc/dubbo-rpc-thrift/src/test/java/com/alibaba/dubbo/rpc/protocol/thrift/AbstractTest.java b/dubbo-rpc/dubbo-rpc-thrift/src/test/java/com/alibaba/dubbo/rpc/protocol/thrift/AbstractTest.java
index 742e1a5..13e8d5f 100644
--- a/dubbo-rpc/dubbo-rpc-thrift/src/test/java/com/alibaba/dubbo/rpc/protocol/thrift/AbstractTest.java
+++ b/dubbo-rpc/dubbo-rpc-thrift/src/test/java/com/alibaba/dubbo/rpc/protocol/thrift/AbstractTest.java
@@ -102,12 +102,12 @@
             invoker = null;
         }
 
-        try{
-            if(serverTransport != null){
+        try {
+            if (serverTransport != null) {
                 // release port if used
                 serverTransport.close();
             }
-        }catch (Exception e) {
+        } catch (Exception e) {
             // ignore
         }
 
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractDeserializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractDeserializer.java
index e3e6c5e..1946f4a 100644
--- a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractDeserializer.java
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractDeserializer.java
@@ -80,7 +80,7 @@
 
     @Override
     public Object readList(AbstractHessianInput in, int length, Class<?> expectType) throws IOException {
-        if(expectType == null) {
+        if (expectType == null) {
             return readList(in, length);
         }
         throw new UnsupportedOperationException(String.valueOf(this));
@@ -94,8 +94,8 @@
 
     @Override
     public Object readLengthList(AbstractHessianInput in, int length, Class<?> expectType) throws IOException {
-        if(expectType == null){
-            return readLengthList(in , length);
+        if (expectType == null) {
+            return readLengthList(in, length);
         }
         throw new UnsupportedOperationException(String.valueOf(this));
     }
@@ -115,7 +115,7 @@
 
     @Override
     public Object readMap(AbstractHessianInput in, Class<?> expectKeyType, Class<?> expectValueType) throws IOException {
-        if(expectKeyType  == null && expectValueType == null){
+        if (expectKeyType == null && expectValueType == null) {
             return readMap(in);
         }
         throw new UnsupportedOperationException(String.valueOf(this));
@@ -140,12 +140,11 @@
 
     protected SerializerFactory findSerializerFactory(AbstractHessianInput in) {
         SerializerFactory serializerFactory = null;
-        if(in instanceof Hessian2Input) {
+        if (in instanceof Hessian2Input) {
             serializerFactory = ((Hessian2Input) in).findSerializerFactory();
-        }
-        else if(in instanceof HessianInput) {
+        } else if (in instanceof HessianInput) {
             serializerFactory = ((HessianInput) in).getSerializerFactory();
         }
-        return serializerFactory == null? new SerializerFactory(): serializerFactory;
+        return serializerFactory == null ? new SerializerFactory() : serializerFactory;
     }
 }
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianInput.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianInput.java
index 7d265de..1d63fec 100644
--- a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianInput.java
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianInput.java
@@ -340,10 +340,10 @@
      *
      * @param expectedClass the expected class if the protocol doesn't supply it.
      * @param expectedTypes the runtime type hints, eg: expectedClass equals Map, expectedTypes can
-     * equals String.class, Short.class
+     *                      equals String.class, Short.class
      */
     public Object readObject(Class expectedClass, Class<?>... expectedTypes)
-        throws IOException{
+            throws IOException {
         throw new UnsupportedOperationException(String.valueOf(this));
     }
 
@@ -355,11 +355,12 @@
 
     /**
      * Reads an arbitrary object from the input stream.
+     *
      * @param expectedTypes the runtime type hints, eg: expectedTypes can
-     * equals String.class, Short.class for HashMap
+     *                      equals String.class, Short.class for HashMap
      */
     public Object readObject(List<Class<?>> expectedTypes)
-        throws IOException{
+            throws IOException {
         throw new UnsupportedOperationException(String.valueOf(this));
     }
 
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/CollectionDeserializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/CollectionDeserializer.java
index 2d3390b..1d3bc89 100644
--- a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/CollectionDeserializer.java
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/CollectionDeserializer.java
@@ -87,7 +87,7 @@
         Deserializer deserializer = null;
 
         SerializerFactory factory = findSerializerFactory(in);
-        if(expectType != null){
+        if (expectType != null) {
             deserializer = factory.getDeserializer(expectType.getName());
         }
 
@@ -114,7 +114,7 @@
         Deserializer deserializer = null;
 
         SerializerFactory factory = findSerializerFactory(in);
-        if(expectType != null){
+        if (expectType != null) {
             deserializer = factory.getDeserializer(expectType.getName());
         }
 
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Deserializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Deserializer.java
index 86d0bb3..d8b6824 100644
--- a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Deserializer.java
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Deserializer.java
@@ -64,7 +64,6 @@
             throws IOException;
 
     /**
-     *
      * deserialize list object from expect type.
      *
      * @param in
@@ -74,13 +73,12 @@
      * @throws IOException
      */
     public Object readList(AbstractHessianInput in, int length, Class<?> expectType)
-        throws IOException;
+            throws IOException;
 
     public Object readLengthList(AbstractHessianInput in, int length)
             throws IOException;
 
     /**
-     *
      * deserialize list object from expect type.
      *
      * @param in
@@ -90,7 +88,7 @@
      * @throws IOException
      */
     public Object readLengthList(AbstractHessianInput in, int length, Class<?> expectType)
-        throws IOException;
+            throws IOException;
 
     public Object readMap(AbstractHessianInput in)
             throws IOException;
@@ -103,8 +101,8 @@
      * @return
      * @throws IOException
      */
-    public Object readMap(AbstractHessianInput in, Class<?> expectKeyType, Class<?> expectValueType )
-        throws IOException;
+    public Object readMap(AbstractHessianInput in, Class<?> expectKeyType, Class<?> expectValueType)
+            throws IOException;
 
     public Object readObject(AbstractHessianInput in, String[] fieldNames)
             throws IOException;
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Input.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Input.java
index 85d18a9..8d6d7d7 100644
--- a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Input.java
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Input.java
@@ -55,7 +55,6 @@
 import java.io.Reader;
 import java.lang.reflect.Field;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
@@ -2092,8 +2091,8 @@
                 boolean keyValuePair = expectedTypes != null && expectedTypes.length == 2;
                 // fix deserialize of short type
                 return reader.readMap(this
-                            , keyValuePair ? expectedTypes[0] : null
-                            , keyValuePair ? expectedTypes[1] : null);
+                        , keyValuePair ? expectedTypes[0] : null
+                        , keyValuePair ? expectedTypes[1] : null);
             }
 
             case 'M': {
@@ -2213,7 +2212,7 @@
                 boolean valueType = expectedTypes != null && expectedTypes.length == 1;
 
                 // fix deserialize of short type
-                Object v = reader.readList(this, -1,  valueType ? expectedTypes[0] : null);
+                Object v = reader.readList(this, -1, valueType ? expectedTypes[0] : null);
 
                 return v;
             }
@@ -2392,7 +2391,7 @@
             case 0xd6:
             case 0xd7:
                 return Integer.valueOf(((tag - BC_INT_SHORT_ZERO) << 16)
-                    + 256 * read() + read());
+                        + 256 * read() + read());
 
             case 'I':
                 return Integer.valueOf(parseInt());
@@ -2702,8 +2701,8 @@
                 reader = findSerializerFactory().getDeserializer(Map.class);
 
                 return reader.readMap(this
-                    , keyValuePair ? expectedTypes.get(0) : null
-                    , keyValuePair ? expectedTypes.get(1) : null);
+                        , keyValuePair ? expectedTypes.get(0) : null
+                        , keyValuePair ? expectedTypes.get(1) : null);
             }
 
             case 'M': {
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/JavaDeserializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/JavaDeserializer.java
index fb5b312..229f685 100644
--- a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/JavaDeserializer.java
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/JavaDeserializer.java
@@ -66,7 +66,7 @@
  */
 public class JavaDeserializer extends AbstractMapDeserializer {
     private static final Logger log
-        = Logger.getLogger(JavaDeserializer.class.getName());
+            = Logger.getLogger(JavaDeserializer.class.getName());
 
     private Class _type;
     private HashMap _fieldMap;
@@ -156,10 +156,10 @@
     }
 
     static void logDeserializeError(Field field, Object obj, Object value,
-        Throwable e)
-        throws IOException {
+                                    Throwable e)
+            throws IOException {
         String fieldName = (field.getDeclaringClass().getName()
-            + "." + field.getName());
+                + "." + field.getName());
 
         if (e instanceof HessianFieldException)
             throw (HessianFieldException) e;
@@ -168,7 +168,7 @@
 
         if (value != null)
             throw new HessianFieldException(fieldName + ": " + value.getClass().getName() + " (" + value + ")"
-                + " cannot be assigned to '" + field.getType().getName() + "'", e);
+                    + " cannot be assigned to '" + field.getType().getName() + "'", e);
         else
             throw new HessianFieldException(fieldName + ": " + field.getType().getName() + " cannot be assigned from null", e);
     }
@@ -180,7 +180,7 @@
 
     @Override
     public Object readMap(AbstractHessianInput in)
-        throws IOException {
+            throws IOException {
         try {
             Object obj = instantiate();
 
@@ -196,7 +196,7 @@
 
     @Override
     public Object readObject(AbstractHessianInput in, String[] fieldNames)
-        throws IOException {
+            throws IOException {
         try {
             Object obj = instantiate();
 
@@ -221,7 +221,7 @@
                 Method method = methods[i];
 
                 if (method.getName().equals("readResolve") &&
-                    method.getParameterTypes().length == 0)
+                        method.getParameterTypes().length == 0)
                     return method;
             }
         }
@@ -230,7 +230,7 @@
     }
 
     public Object readMap(AbstractHessianInput in, Object obj)
-        throws IOException {
+            throws IOException {
         try {
             int ref = in.addRef(obj);
 
@@ -261,9 +261,9 @@
     }
 
     public Object readObject(AbstractHessianInput in,
-        Object obj,
-        String[] fieldNames)
-        throws IOException {
+                             Object obj,
+                             String[] fieldNames)
+            throws IOException {
         try {
             int ref = in.addRef(obj);
 
@@ -292,7 +292,7 @@
     }
 
     private Object resolve(Object obj)
-        throws Exception {
+            throws Exception {
         // if there's a readResolve method, call it
         try {
             if (_readResolve != null)
@@ -306,7 +306,7 @@
     }
 
     protected Object instantiate()
-        throws Exception {
+            throws Exception {
         try {
             if (_constructor != null)
                 return _constructor.newInstance(_constructorArgs);
@@ -329,7 +329,7 @@
                 Field field = fields[i];
 
                 if (Modifier.isTransient(field.getModifiers())
-                    || Modifier.isStatic(field.getModifiers()))
+                        || Modifier.isStatic(field.getModifiers()))
                     continue;
                 else if (fieldMap.get(field.getName()) != null)
                     continue;
@@ -368,15 +368,13 @@
                     deser = new SqlTimeFieldDeserializer(field);
                 }
                 // support generic type of map
-                else if(Map.class.equals(type)
-                    && field.getGenericType() != field.getType()){
+                else if (Map.class.equals(type)
+                        && field.getGenericType() != field.getType()) {
                     deser = new ObjectMapFieldDeserializer(field);
-                }
-                else if(List.class.equals(type)
-                    && field.getGenericType() != field.getType()){
+                } else if (List.class.equals(type)
+                        && field.getGenericType() != field.getType()) {
                     deser = new ObjectListFieldDeserializer(field);
-                }
-                else {
+                } else {
                     deser = new ObjectFieldDeserializer(field);
                 }
 
@@ -389,7 +387,7 @@
 
     abstract static class FieldDeserializer {
         abstract void deserialize(AbstractHessianInput in, Object obj)
-            throws IOException;
+                throws IOException;
     }
 
     static class ObjectFieldDeserializer extends FieldDeserializer {
@@ -401,7 +399,7 @@
 
         @Override
         void deserialize(AbstractHessianInput in, Object obj)
-            throws IOException {
+                throws IOException {
             Object value = null;
 
             try {
@@ -423,7 +421,7 @@
 
         @Override
         void deserialize(AbstractHessianInput in, Object obj)
-            throws IOException {
+                throws IOException {
             boolean value = false;
 
             try {
@@ -445,7 +443,7 @@
 
         @Override
         void deserialize(AbstractHessianInput in, Object obj)
-            throws IOException {
+                throws IOException {
             int value = 0;
 
             try {
@@ -467,7 +465,7 @@
 
         @Override
         void deserialize(AbstractHessianInput in, Object obj)
-            throws IOException {
+                throws IOException {
             int value = 0;
 
             try {
@@ -489,16 +487,16 @@
 
         @Override
         void deserialize(AbstractHessianInput in, Object obj)
-            throws IOException {
+                throws IOException {
             Object value = null;
 
             try {
 
-                Type[] types = ((ParameterizedType)_field.getGenericType()).getActualTypeArguments();
+                Type[] types = ((ParameterizedType) _field.getGenericType()).getActualTypeArguments();
                 value = in.readObject(_field.getType(),
-                        isPrimitive(types[0]) ? (Class<?>)types[0] : null,
-                        isPrimitive(types[1]) ? (Class<?>)types[1] : null
-                    );
+                        isPrimitive(types[0]) ? (Class<?>) types[0] : null,
+                        isPrimitive(types[1]) ? (Class<?>) types[1] : null
+                );
 
                 _field.set(obj, value);
             } catch (Exception e) {
@@ -516,14 +514,14 @@
 
         @Override
         void deserialize(AbstractHessianInput in, Object obj)
-            throws IOException {
+                throws IOException {
             Object value = null;
 
             try {
 
-                Type[] types = ((ParameterizedType)_field.getGenericType()).getActualTypeArguments();
+                Type[] types = ((ParameterizedType) _field.getGenericType()).getActualTypeArguments();
                 value = in.readObject(_field.getType(),
-                    isPrimitive(types[0]) ? (Class<?>)types[0] : null
+                        isPrimitive(types[0]) ? (Class<?>) types[0] : null
                 );
 
                 _field.set(obj, value);
@@ -542,7 +540,7 @@
 
         @Override
         void deserialize(AbstractHessianInput in, Object obj)
-            throws IOException {
+                throws IOException {
             int value = 0;
 
             try {
@@ -564,7 +562,7 @@
 
         @Override
         void deserialize(AbstractHessianInput in, Object obj)
-            throws IOException {
+                throws IOException {
             long value = 0;
 
             try {
@@ -586,7 +584,7 @@
 
         @Override
         void deserialize(AbstractHessianInput in, Object obj)
-            throws IOException {
+                throws IOException {
             double value = 0;
 
             try {
@@ -608,7 +606,7 @@
 
         @Override
         void deserialize(AbstractHessianInput in, Object obj)
-            throws IOException {
+                throws IOException {
             double value = 0;
 
             try {
@@ -630,7 +628,7 @@
 
         @Override
         void deserialize(AbstractHessianInput in, Object obj)
-            throws IOException {
+                throws IOException {
             String value = null;
 
             try {
@@ -652,7 +650,7 @@
 
         @Override
         void deserialize(AbstractHessianInput in, Object obj)
-            throws IOException {
+                throws IOException {
             java.sql.Date value = null;
 
             try {
@@ -676,7 +674,7 @@
 
         @Override
         void deserialize(AbstractHessianInput in, Object obj)
-            throws IOException {
+                throws IOException {
             java.sql.Timestamp value = null;
 
             try {
@@ -700,7 +698,7 @@
 
         @Override
         void deserialize(AbstractHessianInput in, Object obj)
-            throws IOException {
+                throws IOException {
             java.sql.Time value = null;
 
             try {
@@ -715,43 +713,42 @@
     }
 
     /**
-     * @see     java.lang.Boolean#TYPE
-     * @see     java.lang.Character#TYPE
-     * @see     java.lang.Byte#TYPE
-     * @see     java.lang.Short#TYPE
-     * @see     java.lang.Integer#TYPE
-     * @see     java.lang.Long#TYPE
-     * @see     java.lang.Float#TYPE
-     * @see     java.lang.Double#TYPE
-     * @see     java.lang.Void#TYPE
+     * @see java.lang.Boolean#TYPE
+     * @see java.lang.Character#TYPE
+     * @see java.lang.Byte#TYPE
+     * @see java.lang.Short#TYPE
+     * @see java.lang.Integer#TYPE
+     * @see java.lang.Long#TYPE
+     * @see java.lang.Float#TYPE
+     * @see java.lang.Double#TYPE
+     * @see java.lang.Void#TYPE
      */
     private static boolean isPrimitive(Type type) {
-        try{
-            if(type != null) {
-                if(type instanceof Class<?>){
-                    Class<?> clazz = (Class<?>)type;
+        try {
+            if (type != null) {
+                if (type instanceof Class<?>) {
+                    Class<?> clazz = (Class<?>) type;
                     return clazz.isPrimitive()
-                        || PRIMITIVE_TYPE.containsKey(clazz.getName());
+                            || PRIMITIVE_TYPE.containsKey(clazz.getName());
                 }
             }
-        }
-        catch (Exception e){
+        } catch (Exception e) {
             // ignore exception
         }
         return false;
     }
 
-    static final Map<String, Boolean> PRIMITIVE_TYPE = new HashMap<String, Boolean>(){
+    static final Map<String, Boolean> PRIMITIVE_TYPE = new HashMap<String, Boolean>() {
         {
-            put(Boolean.class.getName()    , true );
-            put(Character.class.getName()  , true );
-            put(Byte.class.getName()       , true );
-            put(Short.class.getName()      , true );
-            put(Integer.class.getName()    , true );
-            put(Long.class.getName()       , true );
-            put(Float.class.getName()      , true );
-            put(Double.class.getName()     , true );
-            put(Void.class.getName()       , true );
+            put(Boolean.class.getName(), true);
+            put(Character.class.getName(), true);
+            put(Byte.class.getName(), true);
+            put(Short.class.getName(), true);
+            put(Integer.class.getName(), true);
+            put(Long.class.getName(), true);
+            put(Float.class.getName(), true);
+            put(Double.class.getName(), true);
+            put(Void.class.getName(), true);
         }
     };
 }
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/SerializerFactory.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/SerializerFactory.java
index 39bc5c1..b233fdb 100644
--- a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/SerializerFactory.java
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/SerializerFactory.java
@@ -499,7 +499,7 @@
      * Reads the object as a map.
      */
     public Object readMap(AbstractHessianInput in, String type, Class<?> expectKeyType, Class<?> expectValueType)
-        throws HessianProtocolException, IOException {
+            throws HessianProtocolException, IOException {
         Deserializer deserializer = getDeserializer(type);
 
         if (deserializer != null)
diff --git a/hessian-lite/src/test/java/com/alibaba/com/caucho/hessian/io/Hessian2StringShortTest.java b/hessian-lite/src/test/java/com/alibaba/com/caucho/hessian/io/Hessian2StringShortTest.java
index 66a8b80..0b92f47 100644
--- a/hessian-lite/src/test/java/com/alibaba/com/caucho/hessian/io/Hessian2StringShortTest.java
+++ b/hessian-lite/src/test/java/com/alibaba/com/caucho/hessian/io/Hessian2StringShortTest.java
@@ -40,16 +40,16 @@
 
         Hessian2StringShortType stringShort = new Hessian2StringShortType();
         Map<String, Short> stringShortMap = new HashMap<String, Short>();
-        stringShortMap.put("first", (short)0);
-        stringShortMap.put("last", (short)60);
+        stringShortMap.put("first", (short) 0);
+        stringShortMap.put("last", (short) 60);
         stringShort.stringShortMap = stringShortMap;
 
         Hessian2StringShortType deserialize = baseHessian2Serialize(stringShort);
         assertTrue(deserialize.stringShortMap != null);
         assertTrue(deserialize.stringShortMap.size() == 2);
         assertTrue(deserialize.stringShortMap.get("last") instanceof Short);
-        assertEquals(Short.valueOf((short)0), deserialize.stringShortMap.get("first"));
-        assertEquals(Short.valueOf((short)60), deserialize.stringShortMap.get("last"));
+        assertEquals(Short.valueOf((short) 0), deserialize.stringShortMap.get("first"));
+        assertEquals(Short.valueOf((short) 60), deserialize.stringShortMap.get("last"));
     }
 
     @Test
@@ -57,15 +57,15 @@
 
         Hessian2StringShortType stringShort = new Hessian2StringShortType();
         Map<String, Byte> stringByteMap = new HashMap<String, Byte>();
-        stringByteMap.put("first", (byte)0);
-        stringByteMap.put("last", (byte)60);
+        stringByteMap.put("first", (byte) 0);
+        stringByteMap.put("last", (byte) 60);
         stringShort.stringByteMap = stringByteMap;
 
         Hessian2StringShortType deserialize = baseHessian2Serialize(stringShort);
         assertTrue(deserialize.stringByteMap != null);
         assertTrue(deserialize.stringByteMap.size() == 2);
         assertTrue(deserialize.stringByteMap.get("last") instanceof Byte);
-        assertEquals(Byte.valueOf((byte)0), deserialize.stringByteMap.get("first"));
+        assertEquals(Byte.valueOf((byte) 0), deserialize.stringByteMap.get("first"));
         assertEquals(Byte.valueOf((byte) 60), deserialize.stringByteMap.get("last"));
     }
 
@@ -73,8 +73,8 @@
     public void serialize_map_then_deserialize() throws Exception {
 
         Map<String, Short> stringShortMap = new HashMap<String, Short>();
-        stringShortMap.put("first", (short)0);
-        stringShortMap.put("last", (short)60);
+        stringShortMap.put("first", (short) 0);
+        stringShortMap.put("last", (short) 60);
 
         ByteArrayOutputStream bout = new ByteArrayOutputStream();
         Hessian2Output out = new Hessian2Output(bout);
@@ -88,8 +88,8 @@
         assertTrue(deserialize != null);
         assertTrue(deserialize.size() == 2);
         assertTrue(deserialize.get("last") instanceof Short);
-        assertEquals(Short.valueOf((short)0), deserialize.get("first"));
-        assertEquals(Short.valueOf((short)60), deserialize.get("last"));
+        assertEquals(Short.valueOf((short) 0), deserialize.get("first"));
+        assertEquals(Short.valueOf((short) 60), deserialize.get("last"));
     }
 
     @Test
@@ -126,10 +126,10 @@
         Hessian2StringShortType stringShort = new Hessian2StringShortType();
         Map<String, PersonType> stringPersonTypeMap = new HashMap<String, PersonType>();
         stringPersonTypeMap.put("first", new PersonType(
-                "jason.shang", 26, (double) 0.1, (short)1, (byte)2, Arrays.asList((short)1,(short)1)
+                "jason.shang", 26, (double) 0.1, (short) 1, (byte) 2, Arrays.asList((short) 1, (short) 1)
         ));
         stringPersonTypeMap.put("last", new PersonType(
-                "jason.shang2", 52, (double) 0.2, (short)2, (byte)4, Arrays.asList((short)2,(short)2)
+                "jason.shang2", 52, (double) 0.2, (short) 2, (byte) 4, Arrays.asList((short) 2, (short) 2)
         ));
         stringShort.stringPersonTypeMap = stringPersonTypeMap;
 
@@ -149,11 +149,11 @@
 
 
         assertEquals(new PersonType(
-                "jason.shang", 26, (double) 0.1, (short)1, (byte)2, Arrays.asList((short)1,(short)1)
+                "jason.shang", 26, (double) 0.1, (short) 1, (byte) 2, Arrays.asList((short) 1, (short) 1)
         ), deserialize.stringPersonTypeMap.get("first"));
 
         assertEquals(new PersonType(
-                "jason.shang2", 52, (double) 0.2, (short)2, (byte)4, Arrays.asList((short)2,(short)2)
+                "jason.shang2", 52, (double) 0.2, (short) 2, (byte) 4, Arrays.asList((short) 2, (short) 2)
         ), deserialize.stringPersonTypeMap.get("last"));
 
     }
@@ -162,8 +162,8 @@
     public void serialize_list_then_deserialize() throws Exception {
 
         List<Short> shortList = new ArrayList<Short>();
-        shortList.add((short)0);
-        shortList.add((short)60);
+        shortList.add((short) 0);
+        shortList.add((short) 60);
 
         ByteArrayOutputStream bout = new ByteArrayOutputStream();
         Hessian2Output out = new Hessian2Output(bout);
@@ -177,8 +177,8 @@
         assertTrue(deserialize != null);
         assertTrue(deserialize.size() == 2);
         assertTrue(deserialize.get(1) instanceof Short);
-        assertEquals(Short.valueOf((short)0), deserialize.get(0));
-        assertEquals(Short.valueOf((short)60), deserialize.get(1));
+        assertEquals(Short.valueOf((short) 0), deserialize.get(0));
+        assertEquals(Short.valueOf((short) 60), deserialize.get(1));
     }
 
     @Test
diff --git a/hessian-lite/src/test/java/com/alibaba/com/caucho/hessian/io/beans/Hessian2StringShortType.java b/hessian-lite/src/test/java/com/alibaba/com/caucho/hessian/io/beans/Hessian2StringShortType.java
index 5924b23..4bc77c9 100644
--- a/hessian-lite/src/test/java/com/alibaba/com/caucho/hessian/io/beans/Hessian2StringShortType.java
+++ b/hessian-lite/src/test/java/com/alibaba/com/caucho/hessian/io/beans/Hessian2StringShortType.java
@@ -20,9 +20,7 @@
 import java.util.Map;
 
 /**
- *
  * test short serialize & deserialize model
- *
  */
 public class Hessian2StringShortType implements Serializable {
 
@@ -32,7 +30,7 @@
 
     public Map<String, PersonType> stringPersonTypeMap;
 
-    public Hessian2StringShortType(){
+    public Hessian2StringShortType() {
 
     }
 }
diff --git a/hessian-lite/src/test/java/com/alibaba/com/caucho/hessian/io/beans/PersonType.java b/hessian-lite/src/test/java/com/alibaba/com/caucho/hessian/io/beans/PersonType.java
index 4d3a9eb..7e37c99 100644
--- a/hessian-lite/src/test/java/com/alibaba/com/caucho/hessian/io/beans/PersonType.java
+++ b/hessian-lite/src/test/java/com/alibaba/com/caucho/hessian/io/beans/PersonType.java
@@ -25,7 +25,7 @@
     int age;
     double money;
     short p1;
-    byte  p2;
+    byte p2;
     List<Short> p3;
 
     public PersonType(String name, int age, double money, short p1, byte p2, List<Short> p3) {
diff --git a/pom.xml b/pom.xml
index fa9992f..e45ca67 100644
--- a/pom.xml
+++ b/pom.xml
@@ -333,6 +333,10 @@
                             <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
                             <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                         </manifest>
+                        <manifestEntries>
+                            <Specification-Version>${project.version}</Specification-Version>
+                            <Implementation-Version>${project.version}</Implementation-Version>
+                        </manifestEntries>
                     </archive>
                 </configuration>
             </plugin>