Author: remm
Date: 2014-12-03 08:07:11 +0000 (Wed, 03 Dec 2014)
New Revision: r1643065

URL: http://svn.apache.org/r1643065
Log:

Improve method mapping code so that it attempts to do what is described in 
section 4.8 in the websockets spec.

Modified:
    /tomcat/trunk/java/org/apache/tomcat/websocket/pojo/PojoMethodMapping.java

Index: tomcat/trunk/java/org/apache/tomcat/websocket/pojo/PojoMethodMapping.java
===================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/pojo/PojoMethodMapping.java   
(revision 1643064)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/pojo/PojoMethodMapping.java   
(revision 1643065)
@@ -23,6 +23,7 @@
 import java.lang.reflect.Modifier;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -79,57 +80,106 @@
         Method open = null;
         Method close = null;
         Method error = null;
+        Method[] clazzPojoMethods = null;
         Class<?> currentClazz = clazzPojo;
         while (!currentClazz.equals(Object.class)) {
-            for (Method method : currentClazz.getDeclaredMethods()) {
+            Method[] currentClazzMethods = currentClazz.getDeclaredMethods();
+            if (currentClazz == clazzPojo) {
+                clazzPojoMethods = currentClazzMethods;
+            }
+            for (Method method : currentClazzMethods) {
                 if (method.getAnnotation(OnOpen.class) != null) {
                     checkPublic(method);
                     if (open == null) {
                         open = method;
                     } else {
-                        // Duplicate annotation
-                        throw new DeploymentException(sm.getString(
-                                "pojoMethodMapping.duplicateAnnotation",
-                                OnOpen.class, clazzPojo));
+                        if (currentClazz == clazzPojo ||
+                                (currentClazz != clazzPojo && 
!isMethodOverride(open, method))) {
+                            // Duplicate annotation
+                            throw new DeploymentException(sm.getString(
+                                    "pojoMethodMapping.duplicateAnnotation",
+                                    OnOpen.class, currentClazz));
+                        }
                     }
                 } else if (method.getAnnotation(OnClose.class) != null) {
                     checkPublic(method);
                     if (close == null) {
                         close = method;
                     } else {
-                        // Duplicate annotation
-                        throw new DeploymentException(sm.getString(
-                                "pojoMethodMapping.duplicateAnnotation",
-                                OnClose.class, clazzPojo));
+                        if (currentClazz == clazzPojo ||
+                                (currentClazz != clazzPojo && 
!isMethodOverride(close, method))) {
+                            // Duplicate annotation
+                            throw new DeploymentException(sm.getString(
+                                    "pojoMethodMapping.duplicateAnnotation",
+                                    OnClose.class, currentClazz));
+                        }
                     }
                 } else if (method.getAnnotation(OnError.class) != null) {
                     checkPublic(method);
                     if (error == null) {
                         error = method;
                     } else {
-                        // Duplicate annotation
-                        throw new DeploymentException(sm.getString(
-                                "pojoMethodMapping.duplicateAnnotation",
-                                OnError.class, clazzPojo));
+                        if (currentClazz == clazzPojo ||
+                                (currentClazz != clazzPojo && 
!isMethodOverride(error, method))) {
+                            // Duplicate annotation
+                            throw new DeploymentException(sm.getString(
+                                    "pojoMethodMapping.duplicateAnnotation",
+                                    OnError.class, currentClazz));
+                        }
                     }
                 } else if (method.getAnnotation(OnMessage.class) != null) {
                     checkPublic(method);
                     MessageHandlerInfo messageHandler = new 
MessageHandlerInfo(method, decoders);
+                    boolean found = false;
                     for (MessageHandlerInfo otherMessageHandler : onMessage) {
                         if (messageHandler.equals(otherMessageHandler)) {
-                            // Duplicate annotation
-                            throw new DeploymentException(sm.getString(
-                                    "pojoMethodMapping.duplicateAnnotation",
-                                    OnMessage.class, clazzPojo));
+                            found = true;
+                            if (currentClazz == clazzPojo ||
+                                    (currentClazz != clazzPojo
+                                    && !isMethodOverride(messageHandler.m, 
otherMessageHandler.m))) {
+                                // Duplicate annotation
+                                throw new DeploymentException(sm.getString(
+                                        
"pojoMethodMapping.duplicateAnnotation",
+                                        OnMessage.class, currentClazz));
+                            }
                         }
                     }
-                    onMessage.add(messageHandler);
+                    if (!found) {
+                        onMessage.add(messageHandler);
+                    }
                 } else {
                     // Method not annotated
                 }
             }
             currentClazz = currentClazz.getSuperclass();
         }
+        // If the methods are not on clazzPojo and they are overridden
+        // by a non annotated method in clazzPojo, they should be ignored
+        if (open != null && open.getDeclaringClass() != clazzPojo) {
+            if (isOverridenWithoutAnnotation(clazzPojoMethods, open, 
OnOpen.class)) {
+                open = null;
+            }
+        }
+        if (close != null && close.getDeclaringClass() != clazzPojo) {
+            if (isOverridenWithoutAnnotation(clazzPojoMethods, close, 
OnClose.class)) {
+                close = null;
+            }
+        }
+        if (error != null && error.getDeclaringClass() != clazzPojo) {
+            if (isOverridenWithoutAnnotation(clazzPojoMethods, error, 
OnError.class)) {
+                error = null;
+            }
+        }
+        List<MessageHandlerInfo> overriddenOnMessage = new ArrayList<>();
+        for (MessageHandlerInfo messageHandler : onMessage) {
+            if (messageHandler.m.getDeclaringClass() != clazzPojo
+                    && isOverridenWithoutAnnotation(clazzPojoMethods, 
messageHandler.m, OnMessage.class)) {
+                overriddenOnMessage.add(messageHandler);
+            }
+        }
+        for (MessageHandlerInfo messageHandler : overriddenOnMessage) {
+            onMessage.remove(messageHandler);
+        }
         this.onOpen = open;
         this.onClose = close;
         this.onError = error;
@@ -147,6 +197,25 @@
     }
 
 
+    private boolean isMethodOverride(Method method1, Method method2) {
+        return (method1.getName().equals(method2.getName())
+                && method1.getReturnType().equals(method2.getReturnType())
+                && Arrays.equals(method1.getParameterTypes(), 
method2.getParameterTypes()));
+    }
+
+
+    private boolean isOverridenWithoutAnnotation(Method[] methods,
+            Method superclazzMethod, Class<? extends Annotation> annotation) {
+        for (Method method : methods) {
+            if (isMethodOverride(method, superclazzMethod)
+                    && (method.getAnnotation(annotation) == null)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
     public String getWsPath() {
         return wsPath;
     }

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to