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